Math::BigInt
Revision as of 08:23, 3 April 2005 by 161.253.9.181 (talk) (→Converting a binary string to a BigInt)
Use
Specifying lib
forces a library, but if that library isn't installed, fallback is automatic.
use Math::BigInt lib => 'GMP';
In-place Modification
Modification is in-place, regardless of context. A new object is not created for a result.
use Math::BigInt; # Void context my $a = new Math::BigInt '27'; $a->badd(3); print "$a"; # 30 # Scalar context my $b = new Math::BigInt '27'; my $c = $b->badd(3); print "$b"; # 30 print "$c"; # 30 print $b == $c ? "Same object" : "Not same object"; # Same object
Converting a binary string to a BigInt
Actually, I've implemented something much cooler that exploits Math::BigInt's ability to parse hex strings. The updated code is part of the new Xana library Xana::Math::RawDataUtil.
use Math::BigInt lib => 'GMP'; # This function works by decoding a binary string # 3 bytes at a time (4 could cause sign trouble). # Anything that comes from this function is unsigned. sub bin2ubig { my $len = length($_[0]); my $off = 0; my $cml = Math::BigInt->new('0'); if($len == 0) { return $cml; } my $sub; # The first get is the length % 3. # This way, the rest of the gets # can just be 3. { my $get = $len % 3; # But if the length is a multiple of three, # cut to the main part. last unless $get; $sub = "\0" . substr($_[0],$off,$get); $sub = "\0" . $sub while length($sub) < 4; ($sub) = unpack('N',$sub); $cml->badd($sub); $off += $get; } # All right, now the remainder of the data # is a multiple of three bytes. for(; $off < $len; $off += 3) { # Shift the existing number # left by 24 bits. $cml->bmul(0x1000000); # Decode a new part and add it. ($sub) = unpack('N', "\0" . substr($_[0],$off,3)); $cml->badd($sub); } # That should be it. return $cml; } # This function decodes a binary string to its ones- # complement form. sub binnot { my $oc = ""; my $off = 0; my $len = length($_[0]); my($a,$b,$c,$d,$e,$f,$g,$h); use integer; while($len >= 16) { ($a,$b,$c,$d,$e,$f,$g,$h) = unpack('SSSSSSSS',substr($_[0],$off,16)); $a = ~$a & 0xFFFF; $b = ~$b & 0xFFFF; $c = ~$c & 0xFFFF; $d = ~$d & 0xFFFF; $e = ~$e & 0xFFFF; $f = ~$f & 0xFFFF; $g = ~$g & 0xFFFF; $h = ~$h & 0xFFFF; $oc .= pack('SSSSSSSS', $a,$b,$c,$d,$e,$f,$g,$h); $off += 16; $len -= 16 } while($len >= 8) { ($a,$b,$c,$d) = unpack('SSSS',substr($_[0],$off,8)); $a = ~$a & 0xFFFF; $b = ~$b & 0xFFFF; $c = ~$c & 0xFFFF; $d = ~$d & 0xFFFF; $oc .= pack('SSSS',$a,$b,$c,$d); $off += 8; $len -= 8; } while($len) { $a = unpack('C',substr($_[0],$off,1)); $a = ~$a & 0xFF; $oc .= pack('C',$a); $off += 1; $len -= 1; } return $oc; } # This function detects a twos-complement negative. # If negative, the string is converted to its # ones-complement, processed, and increased by one. sub bin2sbig { return Math::BigInt->new('0') unless length($_[0]); # Is it negative? unless( unpack('C',substr($_[0],0,1)) & 0x80 ) { # No. return bin2ubig(@_); } # Yes. return bin2ubig(scalar binnot($_[0]))->bnot(); }