Difference between revisions of "Math::BigInt"

From HalfgeekKB
Jump to navigation Jump to search
Line 30: Line 30:
 
=Converting a binary string to a BigInt=
 
=Converting a binary string to a BigInt=
  
  # Code here...
+
  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();
 }

See Also