#!/usr/bin/perl -w use strict; use warnings; $| = 1; RunTests( '', '0', 'what?', '0', '0', '0', '1', '1', '11', '3', '0001', '1', '1011', '11', '1111', '15', '11111111', '255', 'yay 1__1 Lol', '3', '11111111111111111111111111111111', '4294967295', '10101010101010101010101010101010', '2863311530', '00000000001111111111110000000000', '4193280', '100011111111110011111011001101000', '4831442536', # 33-bit value '11111111111000111111111100111110110010001000110', '140677352481862', # 47-bit value '111111111111000000000000000000000000000000000000', '281406257233920', # 48-bit value '1111111111110000000000000000000000000000000000000', '562812514467840', # 49-bit value '0000111000111000111000111000111000111000111000111000111000111000', '1024819115206086200', # 60-bit value '1111111111111111100000000000000001111111111111111000000000000000', '18446603338368647168', # 64-bit value '1100111100100110000001111110111000110101010101010101010101010101', '14926626734644483413', # 64-bit value '1111111111111111111111111111111111111111111111111111111111111111', '18446744073709551615', # 64-bit value '10000000000000000000000000000000000000000000000000000000000000000', '18446744073709551616', # 65-bit value # 112-bit value: '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', '5192296858534827628530496329220095', '10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', '5192296858534827628530496329220096', # 360-bit value: '111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', '2348542582773833227889480596789337027375682548908319870707290971532209025114608443463698998384768703031934975', # 1500-bit value: '100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', '17537331055217019373813793980140428996762007940165414412037899012395481925281661101828540443292484630826575203397718758699647274470734979877085519459002350423944978242664548632243401355791731473268341092170069314725677729132473171262691809694657480322332526275875721167754624586680565177898054854942790337156977105108828923716313380366502376637658596066837351781686391648520996613526331666834254976000087526677764529440217091269193357761841856604274688' ); print "\nDon't panic. Your computer did not crash.\nThe following operation may take a few seconds.\n"; print "\nConverting 4096-digit binary number to decimal using Bin2Dec() and Bin2BigInt()\nPlease wait..."; # Generate a 4096-digit binary number: RunTests('1' . '0' x 4096, '1044388881413152506691752710716624382579964249047383780384233483283953907971557456848826811934997558340890106714439262837987573438185793607263236087851365277945956976543709998340361590134383718314428070011855946226376318839397712745672334684344586617496807908705803704071284048740118609114467977783598029006686938976881787785946905630190260940599579453432823469303026696443059025015972399867714215541693835559885291486318237914434496734087811872639496475100189041349008417061675093668333850551032972088269550769983616369411933015213796825837188091833656751221318492846368125550225998300412344784862595674492194617023806505913245610825731835380087608622102834270197698202313169017678006675195485079921636419370285375124784014907159135459982790513399611551794271106831134090584272884279791554849782954323534517065223269061394905987693002122963395687782878948440616007412945674919823050571642377154816321380631045902916136926708342856440730447899971901781465763473223850267253059899795996090799469201774624817718449867455659250178329070473119433165550807568221846571746373296884912819520317457002440926616910874148385078411929804522981857338977648103126085903001302413467189726673216491511131602920781738033436090243804708340403154190336'); print "\nConverting 8192-digit binary number to decimal using Bin2Dec() and Bin2BigInt()\nPlease wait..."; # Generate a 8192-digit binary number: RunTests('1' . '0' x 8192, '1090748135619415929462984244733782862448264161996232692431832786189721331849119295216264234525201987223957291796157025273109870820177184063610979765077554799078906298842192989538609825228048205159696851613591638196771886542609324560121290553901886301017900252535799917200010079600026535836800905297805880952350501630195475653911005312364560014847426035293551245843928918752768696279344088055617515694349945406677825140814900616105920256438504578013326493565836047242407382442812245131517757519164899226365743722432277368075027627883045206501792761700945699168497257879683851737049996900961120515655050115561271491492515342105748966629547032786321505730828430221664970324396138635251626409516168005427623435996308921691446181187406395310665404885739434832877428167407495370993511868756359970390117021823616749458620969857006263612082706715408157066575137281027022310927564910276759160520878304632411049364568754920967322982459184763427383790272448438018526977764941072715611580434690827459339991961414242741410599117426060556483763756314527611362658628383368621157993638020878537675545336789915694234433955666315070087213535470255670312004130725495834508357439653828936077080978550578912967907352780054935621561090795845172954115972927479877527738560008204118558930004777748727761853813510493840581861598652211605960308356405941821189714037868726219481498727603653616298856174822413033485438785324024751419417183012281078209729303537372804574372095228703622776363945290869806258422355148507571039619387449629866808188769662815778153079393179093143648340761738581819563002994422790754955061288818308430079648693232179158765918035565216157115402992120276155607873107937477466841528362987708699450152031231862594203085693838944657061346236704234026821102958954951197087076546186622796294536451620756509351018906023773821539532776208676978589731966330308893304665169436185078350641568336944530051437491311298834367265238595404904273455928723949525227184617404367854754610474377019768025576605881038077270707717942221977090385438585844095492116099852538903974655703943973086090930596963360767529964938414598185705963754561497355827813623833288906309004288017321424808663962671333528009232758350873059614118723781422101460198615747386855096896089189180441339558524822867541113212638793675567650340362970031930023397828465318547238244232028015189689660418822976000815437610652254270163595650875433851147123214227266605403581781469090806576468950587661997186505665475715792896'); print "\nNow we will convert 5000 random 128-bit binary numbers using Bin2BigInt().\nPress ENTER to begin..."; $a = ; my $DEC; my $TIME = time; for (my $count = 0; $count < 5000; $count++) { my $random = ''; for (my $bits = 0; $bits < 128; $bits++) { $random .= (rand(300) > 150) ? '1' : '0'; } $DEC = Bin2BigInt($random); print "\n $random => $DEC"; } print("\n", time - $TIME, ' secs.'); print "\n\nNow we will convert 5000 random 128-bit binary numbers using Bin2Dec().\nPress ENTER to begin..."; $a = ; $TIME = time; for (my $count = 0; $count < 5000; $count++) { my $random = ''; for (my $bits = 0; $bits < 128; $bits++) { $random .= (rand(300) > 150) ? '1' : '0'; } $DEC = Bin2Dec($random); print "\n $random => $DEC"; } print("\n", time - $TIME, ' secs.'); print "\n\n"; exit; #################################################################### # RUN TESTS: # sub RunTests { my $i = 0; my $ERR = 0; while ($i < @_) { my $THIS_OK = 1; my $BIN = $_[$i++]; my $CORRECT = $_[$i++]; my $DEC1 = Bin2Dec($BIN); my $DEC2 = Bin2BigInt($BIN); if ($CORRECT ne $DEC1) { print "\nBin2Dec('$BIN') outputs:\n$DEC1 when it should be:\n$CORRECT\n"; $THIS_OK = 0; $ERR++; } if ($CORRECT ne $DEC2) { print "\nBin2BigInt('$BIN') outputs:\n$DEC2 when it should be:\n$CORRECT\n"; $THIS_OK = 0; $ERR++; } $THIS_OK and print "\nOK $DEC1"; } print "\n\n $ERR ERRORS.\n\n"; return !$ERR; } #################################################################### # # This function takes a binary number of any size made up of # 1s and 0s and returns a decimal number (base 10). # # This function can convert a 64-bit or 128-bit binary number to # a decimal number even when 32-bit processor is used. Regardless # of processor architecture, it will work on any machine. # # The input string can contain any number of digits. Any character # other than 1s and 0s is going to be ignored. The output number # is going to be a big integer which may contain hundreds or # even thousands of digits. # # Usage: STRING = Bin2Dec(STRING) # sub Bin2Dec { defined $_[0] or return 0; my $B = $_[0]; $B =~ tr|01||cd; # Remove illegal chars $B =~ s/^0+//; # Remove preceding zeros (my $L = length($B)) or return 0; # Return 0 $L > 32 or return oct('0b' . $B); # Is it 32 bits or less? my $DEC = oct('0b' . substr($B, -32)); # Convert last 32 bits $B = substr($B, 0, -32); # Remove last 32 bits # Convert number up to 49 bits: $L < 50 and return $DEC + oct('0b' . $B) * 4294967296; my $i; my $N; my $PWR = "\x06\x09\x02\x07\x06\x09\x04\x09\x02\x04"; # 4294967296 $DEC =~ tr|0-9|\x00-\x09|; $DEC = reverse($DEC); $L -= 32; my $PWR2 = 4294967296; while ($L-- >= 0) { if (chop($B)) # Is the next binary digit a '1' ? { # Perform simple addition: $DEC += $PWR $i = (length($PWR) >> 2) + 2; while ($i-- > 0) { vec($DEC, $i, 32) += vec($PWR, $i, 32); } # Perform carry operation: while ($DEC =~ s/([^\x00-\x09])(.)/ $N = ord($1); pack('CC', chop($N), $N + ord($2)) /esg) {} $DEC =~ s/([^\x00-\x09])$/ $N = ord($1); pack('CC', chop($N), $N) /es; } # Here we calculate the next power of two. # We shift each byte of $PWR to the left by 1. # The fastest way to do this is using the tr/// operator. # Each digit 0-9 is represented as an ASCII character # from \0 to \x09 and so once shifted, the numbers then # become \x00 to \x12. After this, we perform a carry operation. # Note: $PWR stores numbers backwards, so "4096" would be # represented as "\x06\x09\x00\x04". # Multiply each digit by 2: $PWR =~ tr|\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0C\x0E\x10\x12\x14\x18\x1C\x20\x24\x28\x30\x38\x40\x48\x70|\x00\x02\x04\x06\x08\x0A\x0C\x0E\x10\x12\x14\x18\x1C\x20\x24\x28\x30\x38\x40\x48\x50\x60\x70\x80\x90\xE0|; # Next, we perform the carry operation again: while ($PWR =~ s/([^\x00-\x09]{1})(.)/ $N = ord($1); pack('CC', chop($N), $N + ord($2)) /esg) {} $PWR =~ s/([^\x00-\x09]{1})$/ $N = ord($1); pack('CC', chop($N), $N) /es; } $DEC =~ tr|\x00-\x09|0-9|; $DEC =~ s/0+$//; $DEC = reverse($DEC); return $DEC; } #################################################################### # # This function converts a binary number from base 2 to base 10 # using BIGADD() function which is slower. # Accepts any number of digits. # # Usage: STRING = Bin2BigInt(STRING) # sub Bin2BigInt { my $N = defined $_[0] ? $_[0] : ''; $N =~ tr|01||cd; # Remove everything except 1s and 0s $N =~ s/^0+//; # Remove initial zeros my $L = length($N); if ($L == 0) { return '0'; } if ($L <= 32) { return oct('0b' . $N); } my $OUTPUT = oct('0b' . substr($N, -32)); my $PWR = 4294967296; $L -= 32; while ($L--) { if (length($PWR) < 15) { if (vec($N, $L, 8) == 49) { $OUTPUT += $PWR; } $PWR += $PWR; } else { if (vec($N, $L, 8) == 49) { $OUTPUT = BIGADD($OUTPUT, $PWR); } $PWR = BIGADD($PWR, $PWR); } } return $OUTPUT; } #################################################################### # # This function adds two big positive integers in base 10 and # returns the sum. There is no error checking done, so make sure # to only provide digits in the arguments. Any non-digit character # will mess up the output. # # The 1st and 2nd arguments must contain two big integers that have # to be added. The 3rd and 4th arguments shift these integers to # the left or right before the addition. For example: # BIGADD(4, 5, 1, 0) would shift 4 to the right by 1, # so it would become 40, and then 40 + 5 = 45. # # Usage: BIGINT_SUM = BIGADD(BIGINT_A, BIGINT_B, SHIFT_A, SHIFT_B) # sub BIGADD { no warnings; my $A = defined $_[0] ? $_[0] : ''; my $B = defined $_[1] ? $_[1] : ''; $A =~ s/^0//g; $A =~ tr|0-9||cd; $B =~ s/^0//g; $B =~ tr|0-9||cd; my $AL = length($A) + int($_[2]); my $BL = length($B) + int($_[3]); my $P = ($AL > $BL ? $AL : $BL) + 1; my $CARRY = 0; my $SUM = ''; while ($P--) { my $DIGIT = (($CARRY >> 1) & 1) + (vec($A, --$AL, 8) & 15) + (vec($B, --$BL, 8) & 15); vec($SUM, $P, 8) = $DIGIT + ($CARRY = ($DIGIT > 9) ? 38 : 48); } $SUM =~ s/^0+//; # Discard preceding zeros return (length($SUM)) ? $SUM : 0; }