On the Proof of work blockchain wiki, one can find that the hash
0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9
corresponds to the value 2^239.61238653. My question is, how can one calculate this numeric value of a hash?
First note that the block hash is usually represented as a hexadecimal, little endian value, when you try to convert to decimal. If your system is little-endian:
To convert to decimal in bash/perl:
$ hex=0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9
$ $ perl -le 'use bignum qw/hex/; print hex("0x".$ARGV[0])' --"$hex"
532607621168989936896605052113495566299419916018780134558135832581308350315356027254565114944
or, to get base2 log:
perl -le 'use bignum qw/hex/; print log(hex($ARGV[0]))/log(2)' -- "$hex"
239.6123865298365295145460775449928303015
Which represents 2^239.61238653
Related
There is a file which contains more than 20 million records. I need to use perl to aggregate the numbers and print the TOTAL on the last line. The numbers that I am supposed to aggregate are very big numbers and they could be positive or negative. I am using bignum module of perl to aggregate the numbers. However, it is not showing the correct results. Please advise.
sample.txt (in reality, this file contains more than 20 million records):
12345678910111213.00
14151617181920212.12345
23242526272829301.54321
32333435363738394.23456
-41424344454647489.65432
Expected output (my perl one liner is showing incorrect TOTAL on the last line):
12345678910111213.00
14151617181920212.12345
23242526272829301.54321
32333435363738394.23456
-41424344454647489.65432
TOTAL=<<total_should_be_printed>>
The perl one liner I am using:
perl -Mbignum -ne 'BEGIN{my $sum=0;} s/\r?\n$//; $sum=$sum+$_; print "$_\n"; END{print "TOTAL=$sum"."\n";}' sample.txt
The perl one-liner is showing the TOTAL as 40648913273951600.00 and this is INCORRECT.
EDIT: Following one-liner is showing 40648913273951631.2469 as answer. Now it is really getting weird......
perl -Mbignum -e 'my $num1=Math::BigFloat->new("12345678910111213.00"); my $num2=Math::BigFloat->new("14151617181920212.12345"); my $num3=Math::BigFloat->new("23242526272829301.54321"); my $num4=Math::BigFloat->new("32333435363738394.23456"); my $num5=Math::BigFloat->new("-41424344454647489.65432"); my $sum=$num1+$num2+$num3+$num4+$num5; print $sum."\n";'
Please verify calculation based on Math::BigFloat module.
use strict;
use warnings;
use feature 'say';
use Math::BigFloat;
my $sum = Math::BigFloat->new(0);
$sum->precision(-5);
while( <DATA> ) {
my $x = Math::BigFloat->new($_);
$sum->badd($x);
say $x;
}
say "\nSUM: $sum";
exit 0;
__DATA__
12345678910111213.00
14151617181920212.12345
23242526272829301.54321
32333435363738394.23456
-41424344454647489.65432
Output
12345678910111213
14151617181920212.12345
23242526272829301.54321
32333435363738394.23456
-41424344454647489.65432
SUM: 40648913273951631.24690
The main job of the bignum pragma is to turn literal numbers into Math::BigInt objects. Once assigned to a variable, that variable will also be an object, and any arithmetic operations carried out using it will be done using Math::BigInt operator overloading.
Since you are reading values from a file, they won't automatically be converted into Math::BigInt values. So you need something else to be the object, in this case $sum. By initialising to the literal 0 value as you have done, $sum becomes an object. Unfortunately you declare my $sum within the scope of the BEGIN block. Outside of this scope, $sum refers to a different package variable, which hasn't been initialised into an object.
So you need to declare the variable outside of the BEGIN, or add a literal zero to it to coerce it into an object:
perl -Mbignum -lne' $sum += 0+$_; END {print $sum}'
How can I tell perl that:
print (log(1000)/log(10)."\n");
print int(log(1000)/log(10))."\n";
should both give 3 (and not 2 which the last one surprisingly gives)?
I know why this happens (binary floats are not decimal floats). So I am not asking WHY it happens. I am asking HOW to tell perl to "do the right thing".
Neither log(1000) nor log(10) can be accurately represented by a floating point number, so you end up with something a little less than 3.
$ perl -e'CORE::say sprintf "%.20f", log(1000)/log(10)'
2.99999999999999955591
You want to round instead of truncating.
A solution is to abuse stringification.
say int("".(log(1000)/log(10)));
say int("".(log(1000000)/log(10)));
Or you could use sprintf (slower than stringification above).
say sprintf("%.0f", log(1000)/log(10));
say sprintf("%.0f", log(1000000)/log(10));
I have a need to convert a long decimal number :14245138929982432 in to hexadecimal value whose value is 329BE0DDB29BE0.
But when i am trying to use below piece of code i am getting result as FFFFFFFF.
$l_KeyExpected_UL=14245138929982432;
$hexadeci = sprintf '%X', $l_KeyExpected_UL;
print $hexadeci."\n";\
can Any one please help on this.
You can use the Math::BigInt module, which does all the heavy-lifting behind the bigint pragma
You can't use sprintf under bigint to convert large decimals to hex because its conversions aren't overloaded, but Math::BigInt objects have an as_hex method which returns the number expressed as a hex string, prefixed with 0x
This program wraps the conversion in a subroutine bigint_to_hex, which removes the 0x prefix and changes lower case to upper case
It is unusual now to encounter an installation of Perl that won't handle 64-bit values anyway. But this method will work with any decimal string, as I have demonstrated by converting a value of 1.2E40 as well as the value in your question
It's vital that you pass big integers as strings, because numeric literals will be converted to floating point by the compiler if they exceed the width of an ordinary integer. My program also prints the hex equivalent of the same 1.2E40 value without quotation marks so that you can see the difference
use strict;
use warnings 'all';
use feature 'say';
use Math::BigInt;
my $l_KeyExpected_UL = '14245138929982432';
say bigint_to_hex($l_KeyExpected_UL);
say bigint_to_hex('12345678901234567890123456789012345678901');
say bigint_to_hex(12345678901234567890123456789012345678901);
say bigint_to_hex(1.2E40);
sub bigint_to_hex {
my $hex = Math::BigInt->new(shift)->as_hex;
$hex =~ s/^0x//;
uc $hex;
}
output
329BE0DDB29BE0
2447DB449988978536BF5BBBE40E766C35
2447DB449988B214BEA48F651CA8000000
2343CBEEEA6F2C193478C00E0000000000
If you have a build of Perl with 64-bit integers
A Perl build with 64-bit ints will display the following:
$ perl -V:ivsize
ivsize='8';
If this is what you have, you can simply use
my $i = 14245138929982432;
my $hex = sprintf('%X', $i);
If you have a build of Perl that may not have 64-bit integers
That number requires at least 56 bits to store.
Math::Int64 allows you to access native 64-bit ints.
use Math::Int64 qw( uint64 int64_to_hex );
# Note that the number is provided as a string!
my $i = uint64('14245138929982432');
my $hex = int64_to_hex($i);
You could also use an arbitrary precision library such as Math::BigInt, but it will be necessarily slower. If you're going to do some number crunching with 64-bit ints, you definitely want Math::Int64 instead of Math::BigInt.
I found something strange.
Different behaviors for different versions of perl.
The code is:
$x = -806;
$x = sprintf "0x%x" , $x;
print "$x";
In 5.6.1 i get:
0xfffffcda
In 5.14 i get:
0xfffffffffffffcda
How can i get 32-bit in 5.14 as well?
Thanks!
The thing with negative numbers is they're represented via 2s complement binary. What you're seeing is the result of the word size being larger.
I'm not entirely sure precisely why it would have changed (aside from 14 years and a general move to 64bit), but it's not easy to fix without recompiling perl. I'd suggest that's not a good idea since what you're really trying to get is a stringification.
A simpler solution would be a bitwise AND with the appropriate length bitmask:
$x = -806;
$x = sprintf ("0x%x" , $x & 0xffffffff);
print "$x";
Some addition to the answer above:
The number of digits Perl produces when its sprintf converts to hex depends on the size of the native C data type Perl uses internally to store unsigned integer values. What type that is is determined by Perl's Configure script when it sets things up to compile the Perl interpreter, so it's not exactly something that can be changed at run time. It can also vary from operating system to operating system and machine to machine, so if you run your script in different environments you can't be sure how many hex digits will be produced (a point strongly in favor of Sobrique's suggestion). It's also quite likely that the default native type was changed from a 32-bit one to a 64-bit one at some point during the 14 years since 5.6.1 was released.
If you want to know what type is used in a particular perl installation, perl -MConfig -E 'say $Config{uvtype}' will tell you (modify as needed for pre-5.10 perls).
I'm trying to compare the checksum value of a file.
One variable $a has the checksum (output of md5sum command, only the hexadecimal part)
and the same value is in variable $b.
If I do ($a == $b), I am getting an error, but if I do ($a eq $b) it gives not equal.
Thanks for your answers, it worked in string comparison after trimming the white spaces, though the use of chomp din't work.
You are comparing strings, not numbers, so do use eq.
Also use lc(), and chomp() or $a=~s/^\s+//;$a=~s/\s+$//;.
You do have the pretty decent option of converting the input to numbers with hex() and using ==.
Try:
if (hex($a) == hex($b)){}
This all depends on how well you're handling the output of your md5sum command. Mine looks like this:
dlamblin$ md5 .bash_history
MD5 (.bash_history) = 61a4c02cbd94ad8604874dda16bdd0d6
So I process it with this:
dlamblin$ perl -e '$a=`md5 .bash_history`;$a=~s/^.*= |\s+$//g;print $a,"\n";'
61a4c02cbd94ad8604874dda16bdd0d6
Now I do notice that hex() has an integer overflow error on this so you'll want to use bigint;
dlamblin$ perl -e '
$a=`md5 .bash_history`;$a=~s/^.*= |\s+$//g;print hex($a),"\n";'
Integer overflow in hexadecimal number at -e line 1.
1.29790550043292e+38
dlamblin$ perl -Mbigint -e '
$a=`md5 .bash_history`;$a=~s/^.*= |\s+$//g;print hex($a),"\n";'
129790550043292010470229278762995667158
Make sure that your strings don't have new-lines or other characters at the end. If in doubt, chomp() both then compare. Also (just to cover off the exceedingly obvious), they are both using the same case to encode the hex chars?
If ($a eq $b) is false, then they are indeed not equal. If you've ruled out obvious differences like "filename: " on one of them, you need to look for whitespace or nonprintable character differences. The easy way to do that is:
use Data::Dumper;
$Data::Dumper::Useqq=1;
print Dumper($a);
print Dumper($b);