Difference between revisions of "Math::BigInt"
Jump to navigation
Jump to search
| Line 30: | Line 30: | ||
=Converting a binary string to a BigInt= | =Converting a binary string to a BigInt= | ||
| − | # | + | 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(); | ||
| + | } | ||
=See Also= | =See Also= | ||
* [http://search.cpan.org/~tels/Math-BigInt-1.75/lib/Math/BigInt.pm CPAN] | * [http://search.cpan.org/~tels/Math-BigInt-1.75/lib/Math/BigInt.pm CPAN] | ||
Revision as of 10:17, 2 April 2005
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
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();
}