Merge bignum 0.10, from Tels.
Jarkko Hietaniemi [Sun, 24 Mar 2002 00:21:07 +0000 (00:21 +0000)]
p4raw-id: //depot/perl@15455

15 files changed:
MANIFEST
lib/Math/BigFloat/Trace.pm [new file with mode: 0644]
lib/Math/BigInt/Trace.pm [new file with mode: 0644]
lib/bigint.pm [new file with mode: 0644]
lib/bignum.pm [new file with mode: 0644]
lib/bignum/t/bigint.t [new file with mode: 0755]
lib/bignum/t/bignum.t [new file with mode: 0755]
lib/bignum/t/bigrat.t [new file with mode: 0755]
lib/bignum/t/bn_lite.t [new file with mode: 0755]
lib/bignum/t/br_lite.t [new file with mode: 0755]
lib/bignum/t/option_a.t [new file with mode: 0755]
lib/bignum/t/option_l.t [new file with mode: 0755]
lib/bignum/t/option_p.t [new file with mode: 0755]
lib/bignum/t/trace.t [new file with mode: 0755]
lib/bigrat.pm [new file with mode: 0644]

index 1e226c6..95b908b 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -892,6 +892,20 @@ lib/autouse.t                      See if autouse works
 lib/base.pm                    Establish IS-A relationship at compile time
 lib/Benchmark.pm               Measure execution time
 lib/Benchmark.t                        See if Benchmark works
+lib/Math/BigFloat/Trace.pm     bignum tracing
+lib/Math/BigInt/Trace.pm       bignum tracing
+lib/bigint.pm                  bignum
+lib/bignum.pm                  bignum
+lib/bignum/t/bigint.t          See if bignum works
+lib/bignum/t/bignum.t          See if bignum works
+lib/bignum/t/bigrat.t          See if bignum works
+lib/bignum/t/bn_lite.t         See if bignum works
+lib/bignum/t/br_lite.t         See if bignum works
+lib/bignum/t/option_a.t                See if bignum works
+lib/bignum/t/option_l.t                See if bignum works
+lib/bignum/t/option_p.t                See if bignum works
+lib/bignum/t/trace.t           See if bignum works
+lib/bigrat.pm                  bignum
 lib/bigfloat.pl                        An arbitrary precision floating point package
 lib/bigfloatpl.t               See if bigfloat.pl works
 lib/bigint.pl                  An arbitrary precision integer arithmetic package
diff --git a/lib/Math/BigFloat/Trace.pm b/lib/Math/BigFloat/Trace.pm
new file mode 100644 (file)
index 0000000..871b2a9
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/perl -w
+
+package Math::BigFloat::Trace;
+
+require 5.005_02;
+use strict;
+
+use Exporter;
+use Math::BigFloat;
+use vars qw($VERSION @ISA $PACKAGE @EXPORT_OK
+            $accuracy $precision $round_mode $div_scale);
+
+@ISA = qw(Exporter Math::BigFloat);
+
+$VERSION = 0.01;
+
+use overload;  # inherit overload from BigFloat
+
+# Globals
+$accuracy = $precision = undef;
+$round_mode = 'even';
+$div_scale = 40;
+
+sub new
+{
+        my $proto  = shift;
+        my $class  = ref($proto) || $proto;
+
+        my $value       = shift;
+       my $a = $accuracy; $a = $_[0] if defined $_[0];
+       my $p = $precision; $p = $_[1] if defined $_[1];
+        my $self = Math::BigFloat->new($value,$a,$p,$round_mode);
+
+#      remember, downgrading may return a BigInt, so don't meddle with class   
+#      bless $self,$class;
+
+       print "MBF new '$value' => '$self' (",ref($self),")";
+        return $self;
+}
+
+sub import
+  {
+  print "MBF import ",join(' ',@_);
+  my $self = shift;
+
+  # we catch the constants, the rest goes go BigFloat
+  my @a = ();
+  foreach (@_)
+    {
+    push @a, $_ if $_ ne ':constant';
+    }
+  overload::constant float => sub { $self->new(shift); }; 
+
+  Math::BigFloat->import(@a);          # need it for subclasses
+#  $self->export_to_level(1,$self,@_);         # need this ?
+  }
+
+1;
diff --git a/lib/Math/BigInt/Trace.pm b/lib/Math/BigInt/Trace.pm
new file mode 100644 (file)
index 0000000..4733d22
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/perl -w
+
+package Math::BigInt::Trace;
+
+require 5.005_02;
+use strict;
+
+use Exporter;
+use Math::BigInt;
+use vars qw($VERSION @ISA $PACKAGE @EXPORT_OK
+            $accuracy $precision $round_mode $div_scale);
+
+@ISA = qw(Exporter Math::BigInt);
+
+$VERSION = 0.01;
+
+use overload;  # inherit overload from BigInt
+
+# Globals
+$accuracy = $precision = undef;
+$round_mode = 'even';
+$div_scale = 40;
+
+sub new
+{
+        my $proto  = shift;
+        my $class  = ref($proto) || $proto;
+
+        my $value       = shift;
+       my $a = $accuracy; $a = $_[0] if defined $_[0];
+       my $p = $precision; $p = $_[1] if defined $_[1];
+        my $self = Math::BigInt->new($value,$a,$p,$round_mode);
+       bless $self,$class;
+       print "MBI new '$value' => '$self' (",ref($self),")";
+        return $self;
+}
+
+sub import
+  {
+  print "MBI import ",join(' ',@_);
+  my $self = shift;
+  Math::BigInt::import($self,@_);              # need it for subclasses
+#  $self->export_to_level(1,$self,@_);         # need this ?
+  @_ = ();
+  }
+
+1;
diff --git a/lib/bigint.pm b/lib/bigint.pm
new file mode 100644 (file)
index 0000000..9539fd5
--- /dev/null
@@ -0,0 +1,343 @@
+package bigint;
+require 5.005;
+
+$VERSION = '0.02';
+use Exporter;
+@ISA =       qw( Exporter );
+@EXPORT_OK = qw( ); 
+
+use strict;
+use overload;
+
+############################################################################## 
+
+# These are all alike, and thus faked by AUTOLOAD
+
+my @faked = qw/round_mode accuracy precision div_scale/;
+use vars qw/$VERSION $AUTOLOAD $_lite/;                # _lite for testsuite
+
+sub AUTOLOAD
+  {
+  my $name = $AUTOLOAD;
+
+  $name =~ s/.*:://;    # split package
+  no strict 'refs';
+  foreach my $n (@faked)
+    {
+    if ($n eq $name)
+      {
+      *{"bigint::$name"} = sub 
+        {
+        my $self = shift;
+        no strict 'refs';
+        if (defined $_[0])
+          {
+          Math::BigInt->$name($_[0]);
+          }
+        return Math::BigInt->$name();
+        };
+      return &$name;
+      }
+    }
+  # delayed load of Carp and avoid recursion
+  require Carp;
+  Carp::croak ("Can't call bigint\-\>$name, not a valid method");
+  }
+
+sub upgrade
+  {
+  my $self = shift;
+  no strict 'refs';
+#  if (defined $_[0])
+#    {
+#    $Math::BigInt::upgrade = $_[0];
+#    }
+  return $Math::BigInt::upgrade;
+  }
+
+sub _constant
+  {
+  # this takes a floating point constant string and returns it truncated to
+  # integer. For instance, '4.5' => '4', '1.234e2' => '123' etc
+  my $float = shift;
+
+  # some simple cases first
+  return $float if ($float =~ /^[+-]?[0-9]+$/);                # '+123','-1','0' etc
+  return $float 
+    if ($float =~ /^[+-]?[0-9]+\.?[eE]\+?[0-9]+$/);    # 123e2, 123.e+2
+  return '0' if ($float =~ /^[+-]?[0]*\.[0-9]+$/);     # .2, 0.2, -.1
+  if ($float =~ /^[+-]?[0-9]+\.[0-9]*$/)               # 1., 1.23, -1.2 etc
+    {
+    $float =~ s/\..*//;
+    return $float;
+    }
+  my ($mis,$miv,$mfv,$es,$ev) = Math::BigInt::_split(\$float);
+  return $float if !defined $mis;      # doesn't look like a number to me
+  my $ec = int($$ev);
+  my $sign = $$mis; $sign = '' if $sign eq '+';
+  if ($$es eq '-')
+    {
+    # ignore fraction part entirely
+    if ($ec >= length($$miv))                  # 123.23E-4
+      {
+      return '0';
+      }
+    return $sign . substr ($$miv,0,length($$miv)-$ec); # 1234.45E-2 = 12
+    }
+  # xE+y
+  if ($ec >= length($$mfv))
+    {
+    $ec -= length($$mfv);                      
+    return $sign.$$miv.$$mfv if $ec == 0;      # 123.45E+2 => 12345
+    return $sign.$$miv.$$mfv.'E'.$ec;          # 123.45e+3 => 12345e1
+    }
+  $mfv = substr($$mfv,0,$ec);
+  return $sign.$$miv.$mfv;                     # 123.45e+1 => 1234
+  }
+
+sub import 
+  {
+  my $self = shift;
+
+  # some defaults
+  my $lib = 'Calc';
+
+  my @import = ( ':constant' );                                # drive it w/ constant
+  my @a = @_; my $l = scalar @_; my $j = 0;
+  my ($ver,$trace);                                    # version? trace?
+  my ($a,$p);                                          # accuracy, precision
+  for ( my $i = 0; $i < $l ; $i++,$j++ )
+    {
+    if ($_[$i] =~ /^(l|lib)$/)
+      {
+      # this causes a different low lib to take care...
+      $lib = $_[$i+1] || '';
+      my $s = 2; $s = 1 if @a-$j < 2;  # avoid "can not modify non-existant..."
+      splice @a, $j, $s; $j -= $s; $i++;
+      }
+    elsif ($_[$i] =~ /^(a|accuracy)$/)
+      {
+      $a = $_[$i+1];
+      my $s = 2; $s = 1 if @a-$j < 2;  # avoid "can not modify non-existant..."
+      splice @a, $j, $s; $j -= $s; $i++;
+      }
+    elsif ($_[$i] =~ /^(p|precision)$/)
+      {
+      $p = $_[$i+1];
+      my $s = 2; $s = 1 if @a-$j < 2;  # avoid "can not modify non-existant..."
+      splice @a, $j, $s; $j -= $s; $i++;
+      }
+    elsif ($_[$i] =~ /^(v|version)$/)
+      {
+      $ver = 1;
+      splice @a, $j, 1; $j --;
+      }
+    elsif ($_[$i] =~ /^(t|trace)$/)
+      {
+      $trace = 1;
+      splice @a, $j, 1; $j --;
+      }
+    else { die "unknown option $_[$i]"; }
+    }
+  my $class;
+  $_lite = 0;                                  # using M::BI::L ?
+  if ($trace)
+    {
+    require Math::BigInt::Trace; $class = 'Math::BigInt::Trace';
+    print STDERR "Loading $class";
+    }
+  else
+    {
+    # see if we can find Math::BigInt::Lite
+    if (!defined $a && !defined $p)            # rounding won't work to well
+      {
+      eval 'require Math::BigInt::Lite;';
+      if ($@ eq '')
+        {
+        @import = ( );                         # :constant in Lite, not MBI
+        Math::BigInt::Lite->import( ':constant' );
+        $_lite= 1;                             # signal okay
+        }
+      }
+    require Math::BigInt if $_lite == 0;       # not already loaded?
+    $class = 'Math::BigInt';                   # regardless of MBIL or not
+    } 
+  # Math::BigInt::Trace or plain Math::BigInt
+  $class->import(@import, lib => $lib);
+
+  bigint->accuracy($a) if defined $a;
+  bigint->precision($p) if defined $p;
+  if ($ver)
+    {
+    print "bigint\t\t\t v$VERSION\n";
+    print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite;
+    print "Math::BigInt\t\t v$Math::BigInt::VERSION";
+    my $config = Math::BigInt->config();
+    print " lib => $config->{lib} v$config->{lib_version}\n";
+    exit;
+    }
+  # we take care of floating point constants, since BigFloat isn't available
+  # and BigInt doesn't like them:
+  overload::constant float => sub { Math::BigInt->new( _constant(shift) ); };
+  }
+
+1;
+
+__END__
+
+=head1 NAME
+
+bigint - Transparent big integer support for Perl
+
+=head1 SYNOPSIS
+
+  use bignt;
+
+  $x = 2 + 4.5,"\n";                   # BigInt 6
+  print 2 ** 512;                      # really is what you think it is
+
+=head1 DESCRIPTION
+
+All operators (including basic math operations) are overloaded. Integer
+constants are created as proper BigInts.
+
+Floating point constants are truncated to integer. All results are also
+trunctaed.
+
+=head2 OPTIONS
+
+bigint recognizes some options that can be passed while loading it via use.
+The options can (currently) be either a single letter form, or the long form.
+The following options exist:
+
+=over 2
+
+=item a or accuracy
+
+This sets the accuracy for all math operations. The argument must be greater
+than or equal to zero. See Math::BigInt's bround() function for details.
+
+       perl -Mbigint=a,2 -le 'print 12345+1'
+
+=item p or precision
+
+This sets the precision for all math operations. The argument can be any
+integer. Negative values mean a fixed number of digits after the dot, and
+are <B>ignored</B> since all operations happen in integer space.
+A positive value rounds to this digit left from the dot. 0 or 1 mean round to
+integer and are ignore like negative values.
+
+See Math::BigInt's bfround() function for details.
+
+       perl -Mbignum=p,5 -le 'print 123456789+123'
+
+=item t or trace
+
+This enables a trace mode and is primarily for debugging bigint or
+Math::BigInt.
+
+=item l or lib
+
+Load a different math lib, see L<MATH LIBRARY>.
+
+       perl -Mbigint=l,GMP -e 'print 2 ** 512'
+
+Currently there is no way to specify more than one library on the command
+line. This will be hopefully fixed soon ;)
+
+=item v or version
+
+This prints out the name and version of all modules used and then exits.
+
+       perl -Mbigint=v -e ''
+
+=head2 MATH LIBRARY
+
+Math with the numbers is done (by default) by a module called
+Math::BigInt::Calc. This is equivalent to saying:
+
+       use bigint lib => 'Calc';
+
+You can change this by using:
+
+       use bigint lib => 'BitVect';
+
+The following would first try to find Math::BigInt::Foo, then
+Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
+
+       use bigint lib => 'Foo,Math::BigInt::Bar';
+
+Please see respective module documentation for further details.
+
+=head2 INTERNAL FORMAT
+
+The numbers are stored as objects, and their internals might change at anytime,
+especially between math operations. The objects also might belong to different
+classes, like Math::BigInt, or Math::BigInt::Lite. Mixing them together, even
+with normal scalars is not extraordinary, but normal and expected.
+
+You should not depend on the internal format, all accesses must go through
+accessor methods. E.g. looking at $x->{sign} is not a bright idea since there
+is no guaranty that the object in question has such a hash key, nor is a hash
+underneath at all.
+
+=head2 SIGN
+
+The sign is either '+', '-', 'NaN', '+inf' or '-inf' and stored seperately.
+You can access it with the sign() method.
+
+A sign of 'NaN' is used to represent the result when input arguments are not
+numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively
+minus infinity. You will get '+inf' when dividing a positive number by 0, and
+'-inf' when dividing any negative number by 0.
+
+=head2 METHODS
+
+Since all numbers are now objects, you can use all functions that are part of
+the BigInt API. You can only use the bxxx() notation, and not the fxxx()
+notation, though. 
+
+=head1 MODULES USED
+
+C<bigint> is just a thin wrapper around various modules of the Math::BigInt
+family. Think of it as the head of the family, who runs the shop, and orders
+the others to do the work.
+
+The following modules are currently used by bigint:
+
+       Math::BigInt::Lite      (for speed, and only if it is loadable)
+       Math::BigInt
+
+=head1 EXAMPLES
+
+Some cool command line examples to impress the Python crowd ;) You might want
+to compare them to the results under -Mbignum or -Mbigrat:
+       perl -Mbigint -le 'print sqrt(33)'
+       perl -Mbigint -le 'print 2*255'
+       perl -Mbigint -le 'print 4.5+2*255'
+       perl -Mbigint -le 'print 3/7 + 5/7 + 8/3'
+       perl -Mbigint -le 'print 123->is_odd()'
+       perl -Mbigint -le 'print log(2)'
+       perl -Mbigint -le 'print 2 ** 0.5'
+       perl -Mbigint=a,65 -le 'print 2 ** 0.2'
+
+=head1 LICENSE
+
+This program is free software; you may redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+Especially L<bigrat> as in C<perl -Mbigrat -le 'print 1/3+1/4'> and
+L<bignum> as in C<perl -Mbignum -le 'print sqrt(2)'>.
+
+L<Math::BigInt>, L<Math::BigRat> and L<Math::Big> as well
+as L<Math::BigInt::BitVect>, L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
+
+=head1 AUTHORS
+
+(C) by Tels L<http://bloodgate.com/> in early 2002.
+
+=cut
diff --git a/lib/bignum.pm b/lib/bignum.pm
new file mode 100644 (file)
index 0000000..6e619ac
--- /dev/null
@@ -0,0 +1,326 @@
+package bignum;
+require 5.005;
+
+$VERSION = '0.10';
+use Exporter;
+@ISA =       qw( Exporter );
+@EXPORT_OK = qw( ); 
+
+use strict;
+
+############################################################################## 
+
+# These are all alike, and thus faked by AUTOLOAD
+
+my @faked = qw/round_mode accuracy precision div_scale/;
+use vars qw/$VERSION $AUTOLOAD $_lite/;                # _lite for testsuite
+
+sub AUTOLOAD
+  {
+  my $name = $AUTOLOAD;
+
+  $name =~ s/.*:://;    # split package
+  no strict 'refs';
+  foreach my $n (@faked)
+    {
+    if ($n eq $name)
+      {
+      *{"bignum::$name"} = sub 
+        {
+        my $self = shift;
+        no strict 'refs';
+        if (defined $_[0])
+          {
+          Math::BigInt->$name($_[0]);
+          Math::BigFloat->$name($_[0]);
+          }
+        return Math::BigInt->$name();
+        };
+      return &$name;
+      }
+    }
+  # delayed load of Carp and avoid recursion
+  require Carp;
+  Carp::croak ("Can't call bignum\-\>$name, not a valid method");
+  }
+
+sub upgrade
+  {
+  my $self = shift;
+  no strict 'refs';
+#  if (defined $_[0])
+#    {
+#    $Math::BigInt::upgrade = $_[0];
+#    $Math::BigFloat::upgrade = $_[0];
+#    }
+  return $Math::BigInt::upgrade;
+  }
+
+sub import 
+  {
+  my $self = shift;
+
+  # some defaults
+  my $lib = 'Calc';
+  my $upgrade = 'Math::BigFloat';
+  my $downgrade = 'Math::BigInt';
+
+  my @import = ( ':constant' );                                # drive it w/ constant
+  my @a = @_; my $l = scalar @_; my $j = 0;
+  my ($ver,$trace);                                    # version? trace?
+  my ($a,$p);                                          # accuracy, precision
+  for ( my $i = 0; $i < $l ; $i++,$j++ )
+    {
+    if ($_[$i] eq 'upgrade')
+      {
+      # this causes upgrading
+      $upgrade = $_[$i+1];             # or undef to disable
+      my $s = 2; $s = 1 if @a-$j < 2;  # avoid "can not modify non-existant..."
+      splice @a, $j, $s; $j -= $s; $i++;
+      }
+    elsif ($_[$i] eq 'downgrade')
+      {
+      # this causes downgrading
+      $downgrade = $_[$i+1];           # or undef to disable
+      my $s = 2; $s = 1 if @a-$j < 2;  # avoid "can not modify non-existant..."
+      splice @a, $j, $s; $j -= $s; $i++;
+      }
+    elsif ($_[$i] =~ /^(l|lib)$/)
+      {
+      # this causes a different low lib to take care...
+      $lib = $_[$i+1] || '';
+      my $s = 2; $s = 1 if @a-$j < 2;  # avoid "can not modify non-existant..."
+      splice @a, $j, $s; $j -= $s; $i++;
+      }
+    elsif ($_[$i] =~ /^(a|accuracy)$/)
+      {
+      $a = $_[$i+1];
+      my $s = 2; $s = 1 if @a-$j < 2;  # avoid "can not modify non-existant..."
+      splice @a, $j, $s; $j -= $s; $i++;
+      }
+    elsif ($_[$i] =~ /^(p|precision)$/)
+      {
+      $p = $_[$i+1];
+      my $s = 2; $s = 1 if @a-$j < 2;  # avoid "can not modify non-existant..."
+      splice @a, $j, $s; $j -= $s; $i++;
+      }
+    elsif ($_[$i] =~ /^(v|version)$/)
+      {
+      $ver = 1;
+      splice @a, $j, 1; $j --;
+      }
+    elsif ($_[$i] =~ /^(t|trace)$/)
+      {
+      $trace = 1;
+      splice @a, $j, 1; $j --;
+      }
+    else { die "unknown option $_[$i]"; }
+    }
+  my $class;
+  $_lite = 0;                                  # using M::BI::L ?
+  if ($trace)
+    {
+    require Math::BigInt::Trace; $class = 'Math::BigInt::Trace';
+    $upgrade = 'Math::BigFloat::Trace';        
+    print STDERR "Loading $class";
+    }
+  else
+    {
+    # see if we can find Math::BigInt::Lite
+    if (!defined $a && !defined $p)            # rounding won't work to well
+      {
+      eval 'require Math::BigInt::Lite;';
+      if ($@ eq '')
+        {
+        @import = ( );                         # :constant in Lite, not MBI
+        Math::BigInt::Lite->import( ':constant' );
+        $_lite= 1;                             # signal okay
+        }
+      }
+    require Math::BigInt if $_lite == 0;       # not already loaded?
+    $class = 'Math::BigInt';                   # regardless of MBIL or not
+    } 
+  # Math::BigInt::Trace or plain Math::BigInt
+  $class->import(@import, upgrade => $upgrade, lib => $lib);
+
+  if ($trace)
+    {
+    require Math::BigFloat::Trace; $class = 'Math::BigFloat::Trace';
+    $downgrade = 'Math::BigInt::Trace';        
+    print STDERR "Loading $class";
+    }
+  else
+    {
+    require Math::BigFloat; $class = 'Math::BigFloat';
+    }
+  $class->import(':constant','downgrade',$downgrade);
+
+  bignum->accuracy($a) if defined $a;
+  bignum->precision($p) if defined $p;
+  if ($ver)
+    {
+    print "bignum\t\t\t v$VERSION\n";
+    print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite;
+    print "Math::BigInt\t\t v$Math::BigInt::VERSION";
+    my $config = Math::BigInt->config();
+    print " lib => $config->{lib} v$config->{lib_version}\n";
+    print "Math::BigFloat\t\t v$Math::BigFloat::VERSION\n";
+    exit;
+    }
+  }
+
+1;
+
+__END__
+
+=head1 NAME
+
+bignum - Transparent BigNumber support for Perl
+
+=head1 SYNOPSIS
+
+  use bignum;
+
+  $x = 2 + 4.5,"\n";                   # BigFloat 6.5
+  print 2 ** 512 * 0.1;                        # really is what you think it is
+
+=head1 DESCRIPTION
+
+All operators (including basic math operations) are overloaded. Integer and
+floating-point constants are created as proper BigInts or BigFloats,
+respectively.
+
+=head2 OPTIONS
+
+bignum recognizes some options that can be passed while loading it via use.
+The options can (currently) be either a single letter form, or the long form.
+The following options exist:
+
+=over 2
+
+=item a or accuracy
+
+This sets the accuracy for all math operations. The argument must be greater
+than or equal to zero. See Math::BigInt's bround() function for details.
+
+       perl -Mbignum=a,50 -le 'print sqrt(20)'
+
+=item p or precision
+
+This sets the precision for all math operations. The argument can be any
+integer. Negative values mean a fixed number of digits after the dot, while
+a positive value rounds to this digit left from the dot. 0 or 1 mean round to
+integer. See Math::BigInt's bfround() function for details.
+
+       perl -Mbignum=p,-50 -le 'print sqrt(20)'
+
+=item t or trace
+
+This enables a trace mode and is primarily for debugging bignum or
+Math::BigInt/Math::BigFloat.
+
+=item l or lib
+
+Load a different math lib, see L<MATH LIBRARY>.
+
+       perl -Mbignum=l,GMP -e 'print 2 ** 512'
+
+Currently there is no way to specify more than one library on the command
+line. This will be hopefully fixed soon ;)
+
+=item v or version
+
+This prints out the name and version of all modules used and then exits.
+
+       perl -Mbignum=v -e ''
+
+=head2 MATH LIBRARY
+
+Math with the numbers is done (by default) by a module called
+Math::BigInt::Calc. This is equivalent to saying:
+
+       use bignum lib => 'Calc';
+
+You can change this by using:
+
+       use bignum lib => 'BitVect';
+
+The following would first try to find Math::BigInt::Foo, then
+Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
+
+       use bignum lib => 'Foo,Math::BigInt::Bar';
+
+Please see respective module documentation for further details.
+
+=head2 INTERNAL FORMAT
+
+The numbers are stored as objects, and their internals might change at anytime,
+especially between math operations. The objects also might belong to different
+classes, like Math::BigInt, or Math::BigFLoat. Mixing them together, even
+with normal scalars is not extraordinary, but normal and expected.
+
+You should not depend on the internal format, all accesses must go through
+accessor methods. E.g. looking at $x->{sign} is not a bright idea since there
+is no guaranty that the object in question has such a hashkey, nor is a hash
+underneath at all.
+
+=head2 SIGN
+
+The sign is either '+', '-', 'NaN', '+inf' or '-inf' and stored seperately.
+You can access it with the sign() method.
+
+A sign of 'NaN' is used to represent the result when input arguments are not
+numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively
+minus infinity. You will get '+inf' when dividing a positive number by 0, and
+'-inf' when dividing any negative number by 0.
+
+=head2 METHODS
+
+Since all numbers are now objects, you can use all functions that are part of
+the BigInt or BigFloat API. It is wise to use only the bxxx() notation, and not
+the fxxx() notation, though. This makes it possible that the underlying object
+might morph into a different class than BigFloat.
+
+=head1 MODULES USED
+
+C<bignum> is just a thin wrapper around various modules of the Math::BigInt
+family. Think of it as the head of the family, who runs the shop, and orders
+the others to do the work.
+
+The following modules are currently used by bignum:
+
+       Math::BigInt::Lite      (for speed, and only if it is loadable)
+       Math::BigInt
+       Math::BigFloat
+
+=head1 EXAMPLES
+
+Some cool command line examples to impress the Python crowd ;)
+       perl -Mbignum -le 'print sqrt(33)'
+       perl -Mbignum -le 'print 2*255'
+       perl -Mbignum -le 'print 4.5+2*255'
+       perl -Mbignum -le 'print 3/7 + 5/7 + 8/3'
+       perl -Mbignum -le 'print 123->is_odd()'
+       perl -Mbignum -le 'print log(2)'
+       perl -Mbignum -le 'print 2 ** 0.5'
+       perl -Mbignum=a,65 -le 'print 2 ** 0.2'
+
+=head1 LICENSE
+
+This program is free software; you may redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+Especially L<bigrat> as in C<perl -Mbigrat -le 'print 1/3+1/4'>.
+
+L<Math::BigFloat>, L<Math::BigInt>, L<Math::BigRat> and L<Math::Big> as well
+as L<Math::BigInt::BitVect>, L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
+
+=head1 AUTHORS
+
+(C) by Tels L<http://bloodgate.com/> in early 2002.
+
+=cut
diff --git a/lib/bignum/t/bigint.t b/lib/bignum/t/bigint.t
new file mode 100755 (executable)
index 0000000..6133f7b
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/perl -w
+
+###############################################################################
+
+use Test;
+use strict;
+
+BEGIN
+  {
+  $| = 1;
+  chdir 't' if -d 't';
+  unshift @INC, '../lib';
+  plan tests => 28;
+  }
+
+use bigint;
+
+###############################################################################
+# _constant tests
+
+foreach (qw/ 
+  123:123
+  123.4:123
+  1.4:1
+  0.1:0
+  -0.1:0
+  -1.1:-1
+  -123.4:-123
+  -123:-123
+  123e2:123e2
+  123e-1:12
+  123e-4:0
+  123e-3:0
+  123.345e-1:12
+  123.456e+2:12345
+  1234.567e+3:1234567
+  1234.567e+4:1234567E1
+  1234.567e+6:1234567E3
+  /)
+  {
+  my ($x,$y) = split /:/;
+  print "# Try $x\n";
+  ok (bigint::_constant("$x"),"$y");
+  }
+
+###############################################################################
+# general tests
+
+my $x = 5; ok (ref($x) =~ /^Math::BigInt/);            # :constant
+
+# todo:  ok (2 + 2.5,4.5);                             # should still work
+# todo: $x = 2 + 3.5; ok (ref($x),'Math::BigFloat');
+
+$x = 2 ** 255; ok (ref($x) =~ /^Math::BigInt/);
+
+ok (12->bfac(),479001600);
+ok (9/4,2);
+
+ok (4.5+4.5,8);                                        # truncate
+ok (ref(4.5+4.5) =~ /^Math::BigInt/);
+
+
+###############################################################################
+# accurarcy and precision
+
+# this might change!
+
+ok_undef ($Math::BigInt::accuracy);
+ok_undef ($Math::BigInt::precision);
+bigint->accuracy(5);
+ok ($Math::BigInt::accuracy,5);
+bigint->precision(-2);
+ok_undef ($Math::BigInt::accuracy);
+ok ($Math::BigInt::precision,-2);
+
+###############################################################################
+###############################################################################
+# Perl 5.005 does not like ok ($x,undef)
+
+sub ok_undef
+  {
+  my $x = shift;
+
+  ok (1,1) and return if !defined $x;
+  ok ($x,'undef');
+  }
diff --git a/lib/bignum/t/bignum.t b/lib/bignum/t/bignum.t
new file mode 100755 (executable)
index 0000000..a804a26
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/perl -w
+
+###############################################################################
+
+use Test;
+use strict;
+
+BEGIN
+  {
+  $| = 1;
+  chdir 't' if -d 't';
+  unshift @INC, '../lib';
+  plan tests => 17;
+  }
+
+use bignum;
+
+###############################################################################
+# general tests
+
+my $x = 5; ok (ref($x) =~ /^Math::BigInt/);            # :constant
+
+# todo:  ok (2 + 2.5,4.5);                             # should still work
+# todo: $x = 2 + 3.5; ok (ref($x),'Math::BigFloat');
+
+$x = 2 ** 255; ok (ref($x) =~ /^Math::BigInt/);
+
+# see if Math::BigInt constant and upgrading works
+ok (Math::BigInt::bsqrt(12),'3.464101615137754587054892683011744733886');
+ok (sqrt(12),'3.464101615137754587054892683011744733886');
+
+ok (2/3,"0.6666666666666666666666666666666666666667");
+
+#ok (2 ** 0.5, 'NaN'); # should be sqrt(2);
+
+ok (12->bfac(),479001600);
+
+# see if Math::BigFloat constant works
+
+#                     0123456789          0123456789   <- default 40
+#           0123456789          0123456789
+ok (1/3, '0.3333333333333333333333333333333333333333');
+
+###############################################################################
+# accurarcy and precision
+
+# this might change!
+
+ok_undef ($Math::BigInt::accuracy);
+ok_undef ($Math::BigInt::precision);
+ok_undef ($Math::BigFloat::accuracy);
+ok_undef ($Math::BigFloat::precision);
+bignum->accuracy(5);
+ok ($Math::BigInt::accuracy,5);
+ok ($Math::BigFloat::accuracy,5);
+bignum->precision(-2);
+ok_undef ($Math::BigInt::accuracy);
+ok_undef ($Math::BigFloat::accuracy);
+ok ($Math::BigInt::precision,-2);
+ok ($Math::BigFloat::precision,-2);
+
+###############################################################################
+###############################################################################
+# Perl 5.005 does not like ok ($x,undef)
+
+sub ok_undef
+  {
+  my $x = shift;
+
+  ok (1,1) and return if !defined $x;
+  ok ($x,'undef');
+  }
diff --git a/lib/bignum/t/bigrat.t b/lib/bignum/t/bigrat.t
new file mode 100755 (executable)
index 0000000..3664e8b
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/perl -w
+
+###############################################################################
+
+use Test;
+use strict;
+
+BEGIN
+  {
+  $| = 1;
+  chdir 't' if -d 't';
+  unshift @INC, '../lib';
+  plan tests => 4;
+  }
+
+use bigrat;
+
+###############################################################################
+# general tests
+
+my $x = 5; ok (ref($x),'Math::BigInt');                # :constant
+
+# todo:  ok (2 + 2.5,4.5);                             # should still work
+# todo: $x = 2 + 3.5; ok (ref($x),'Math::BigFloat');
+
+$x = 2 ** 255; ok (ref($x),'Math::BigInt');
+
+# see if Math::BigRat constant works
+ok (1/3, '1/3');
+ok (1/4+1/3,'7/12');
+
+###############################################################################
+# accurarcy and precision
+
+# this might change!
+#ok_undef ($Math::BigInt::accuracy);
+#ok_undef ($Math::BigInt::precision);
+#ok_undef ($Math::BigFloat::accuracy);
+#ok_undef ($Math::BigFloat::precision);
+#bigrat->accuracy(5);
+#ok ($Math::BigInt::accuracy,5);
+#ok ($Math::BigFloat::accuracy,5);
+#bigrat->precision(-2);
+#ok_undef ($Math::BigInt::accuracy);
+#ok_undef ($Math::BigFloat::accuracy);
+#ok ($Math::BigInt::precision,-2);
+#ok ($Math::BigFloat::precision,-2);
+
+###############################################################################
+###############################################################################
+# Perl 5.005 does not like ok ($x,undef)
+
+sub ok_undef
+  {
+  my $x = shift;
+
+  ok (1,1) and return if !defined $x;
+  ok ($x,'undef');
+  }
diff --git a/lib/bignum/t/bn_lite.t b/lib/bignum/t/bn_lite.t
new file mode 100755 (executable)
index 0000000..21247c1
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/perl -w
+
+###############################################################################
+
+use Test;
+use strict;
+
+BEGIN
+  {
+  $| = 1;
+  chdir 't' if -d 't';
+  unshift @INC, '../lib';
+  plan tests => 1;
+  }
+
+eval 'require Math::BigInt::Lite;';
+if ($@ eq '')
+  {
+  # can use Lite, so let bignum try it
+  require bignum; bignum->import();
+  # can't get to work a ref(1+1) here, presumable because :constant phase
+  # already done
+  ok ($bignum::_lite,1);
+  }
+else
+  {
+  print "ok 1 # skipped, no Math::BigInt::Lite\n";
+  }
+  
+
diff --git a/lib/bignum/t/br_lite.t b/lib/bignum/t/br_lite.t
new file mode 100755 (executable)
index 0000000..2bf77d4
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/perl -w
+
+###############################################################################
+
+use Test;
+use strict;
+
+BEGIN
+  {
+  $| = 1;
+  chdir 't' if -d 't';
+  unshift @INC, '../lib';
+  plan tests => 1;
+  }
+
+eval 'require Math::BigInt::Lite;';
+if ($@ eq '')
+  {
+  # can use Lite, so let bignum try it
+  require bigrat; bigrat->import();
+  # can't get to work a ref(1+1) here, presumable because :constant phase
+  # already done
+  ok ($bigrat::_lite,1);
+  }
+else
+  {
+  print "ok 1 # skipped, no Math::BigInt::Lite\n";
+  }
+  
+
diff --git a/lib/bignum/t/option_a.t b/lib/bignum/t/option_a.t
new file mode 100755 (executable)
index 0000000..2ab00bb
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+###############################################################################
+
+use Test;
+use strict;
+
+BEGIN
+  {
+  $| = 1;
+  chdir 't' if -d 't';
+  unshift @INC, '../lib';
+  plan tests => 4;
+  }
+
+use bignum a => '12';
+
+ok (Math::BigInt->accuracy(),12);
+ok (Math::BigFloat->accuracy(),12);
+
+bignum->import( accuracy => '23');
+
+ok (Math::BigInt->accuracy(),23);
+ok (Math::BigFloat->accuracy(),23);
+
diff --git a/lib/bignum/t/option_l.t b/lib/bignum/t/option_l.t
new file mode 100755 (executable)
index 0000000..134dd7c
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/perl -w
+
+###############################################################################
+
+use Test;
+use strict;
+
+BEGIN
+  {
+  $| = 1;
+  chdir 't' if -d 't';
+  unshift @INC, '../lib';
+  plan tests => 12;
+  }
+
+use bignum;
+
+my $rc = eval ('bignum->import( "l" => "foo" );');
+ok ($@,'');                                            # shouldn't die
+$rc = eval ('bignum->import( "lib" => "foo" );');
+ok ($@,'');                                            # ditto
+
+$rc = eval ('bignum->import( "foo" => "bar" );');
+ok ($@ =~ /^Unknown option foo/i,1);                   # should die
+
+# test that options are only lowercase (don't see a reason why allow UPPER)
+
+foreach (qw/L LIB Lib T Trace TRACE V Version VERSION/)
+  {
+  $rc = eval ('bignum->import( "$_" => "bar" );');
+  ok ($@ =~ /^Unknown option $_/i,1);                  # should die
+  }
+
diff --git a/lib/bignum/t/option_p.t b/lib/bignum/t/option_p.t
new file mode 100755 (executable)
index 0000000..c6df4ad
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/perl -w
+
+###############################################################################
+
+use Test;
+use strict;
+
+BEGIN
+  {
+  $| = 1;
+  chdir 't' if -d 't';
+  unshift @INC, '../lib';
+  plan tests => 2;
+  }
+
+use bignum p => '12';
+
+ok (Math::BigInt->precision(),12);
+ok (Math::BigFloat->precision(),12);
+
diff --git a/lib/bignum/t/trace.t b/lib/bignum/t/trace.t
new file mode 100755 (executable)
index 0000000..891101b
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/perl -w
+
+###############################################################################
+
+use Test;
+use strict;
+
+BEGIN
+  {
+  $| = 1;
+  chdir 't' if -d 't';
+  unshift @INC, '../lib';
+  plan tests => 1;
+  }
+
+BEGIN
+  {
+  print "# ";                                  # for testsuite
+  }
+use bignum qw/ trace /;
+
+###############################################################################
+# general tests
+
+my $x = 5; 
+print "\n";
+ok (ref($x),'Math::BigInt::Trace');            # :constant via trace
+
+###############################################################################
+###############################################################################
+# Perl 5.005 does not like ok ($x,undef)
+
+sub ok_undef
+  {
+  my $x = shift;
+
+  ok (1,1) and return if !defined $x;
+  ok ($x,'undef');
+  }
diff --git a/lib/bigrat.pm b/lib/bigrat.pm
new file mode 100644 (file)
index 0000000..ed37875
--- /dev/null
@@ -0,0 +1,242 @@
+package bigrat;
+require 5.005;
+
+$VERSION = '0.04';
+use Exporter;
+@ISA =       qw( Exporter );
+@EXPORT_OK = qw( ); 
+
+use strict;
+
+############################################################################## 
+
+# These are all alike, and thus faked by AUTOLOAD
+
+my @faked = qw/round_mode accuracy precision div_scale/;
+use vars qw/$VERSION $AUTOLOAD $_lite/;                # _lite for testsuite
+
+sub AUTOLOAD
+  {
+  my $name = $AUTOLOAD;
+
+  $name =~ s/.*:://;    # split package
+  no strict 'refs';
+  foreach my $n (@faked)
+    {
+    if ($n eq $name)
+      {
+      *{"bigrat::$name"} = sub 
+        {
+        my $self = shift;
+        no strict 'refs';
+        if (defined $_[0])
+          {
+          Math::BigInt->$name($_[0]);
+          Math::BigFloat->$name($_[0]);
+          }
+        return Math::BigInt->$name();
+        };
+      return &$name;
+      }
+    }
+  # delayed load of Carp and avoid recursion
+  require Carp;
+  Carp::croak ("Can't call bigrat\-\>$name, not a valid method");
+  }
+
+sub upgrade
+  {
+  my $self = shift;
+  no strict 'refs';
+#  if (defined $_[0])
+#    {
+#    $Math::BigInt::upgrade = $_[0];
+#    $Math::BigFloat::upgrade = $_[0];
+#    }
+  return $Math::BigInt::upgrade;
+  }
+
+sub import 
+  {
+  my $self = shift;
+
+  # see also bignum->import() for additional comments
+
+  # some defaults
+  my $lib = 'Calc'; my $upgrade = 'Math::BigFloat';
+
+  my @import = ( ':constant' );                                # drive it w/ constant
+  my @a = @_; my $l = scalar @_; my $j = 0;
+  my ($a,$p);
+  my ($ver,$trace);                                    # version? trace?
+  for ( my $i = 0; $i < $l ; $i++,$j++ )
+    {
+    if ($_[$i] eq 'upgrade')
+      {
+      # this causes upgrading
+      $upgrade = $_[$i+1];             # or undef to disable
+      my $s = 2; $s = 1 if @a-$j < 2;  # avoid "can not modify non-existant..."
+      splice @a, $j, $s; $j -= $s;
+      }
+    elsif ($_[$i] =~ /^(l|lib)$/)
+      {
+      # this causes a different low lib to take care...
+      $lib = $_[$i+1] || '';
+      my $s = 2; $s = 1 if @a-$j < 2;  # avoid "can not modify non-existant..."
+      splice @a, $j, $s; $j -= $s;
+      }
+    elsif ($_[$i] =~ /^(v|version)$/)
+      {
+      $ver = 1;
+      splice @a, $j, 1; $j --;
+      }
+    elsif ($_[$i] =~ /^(t|trace)$/)
+      {
+      $trace = 1;
+      splice @a, $j, 1; $j --;
+      }
+    else
+      {
+      die ("unknown option $_[$i]");
+      }
+    }
+  my $class;
+  $_lite = 0;                                   # using M::BI::L ?
+  if ($trace)
+    {
+    require Math::BigInt::Trace; $class = 'Math::BigInt::Trace';
+    $upgrade = 'Math::BigFloat::Trace';
+    print STDERR "Loading $class";
+    }
+  else
+    {
+    # see if we can find Math::BigInt::Lite
+    if (!defined $a && !defined $p)             # rounding won't work to well
+      {
+      eval 'require Math::BigInt::Lite;';
+      if ($@ eq '')
+        {
+        @import = ( );                          # :constant in Lite, not MBI
+        Math::BigInt::Lite->import( ':constant' );
+        $_lite= 1;                              # signal okay
+        }
+      }
+    require Math::BigInt if $_lite == 0;        # not already loaded?
+    $class = 'Math::BigInt';                    # regardless of MBIL or not
+    }
+  # Math::BigInt::Trace or plain Math::BigInt
+  $class->import(@import, upgrade => $upgrade, lib => $lib);
+
+  require Math::BigFloat;
+  Math::BigFloat->import( upgrade => 'Math::BigRat', ':constant' );
+  require Math::BigRat;
+  if ($ver)
+    {
+    print "bigrat\t\t\t v$VERSION\n";
+    print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite;  
+    print "Math::BigInt\t\t v$Math::BigInt::VERSION";
+    my $config = Math::BigInt->config();
+    print " lib => $config->{lib} v$config->{lib_version}\n";
+    print "Math::BigFloat\t\t v$Math::BigFloat::VERSION\n";
+    print "Math::BigRat\t\t v$Math::BigRat::VERSION\n";
+    exit;
+    }
+  }
+
+1;
+
+__END__
+
+=head1 NAME
+
+bigrat - Transparent BigNumber/BigRationale support for Perl
+
+=head1 SYNOPSIS
+
+  use bigrat;
+
+  $x = 2 + 4.5,"\n";                   # BigFloat 6.5
+  print 1/3 + 1/4,"\n";                        # produces 7/12
+
+=head1 DESCRIPTION
+
+All operators (inlcuding basic math operations) are overloaded. Integer and
+floating-point constants are created as proper BigInts or BigFloats,
+respectively.
+
+Other than L<bignum>, this module upgrades to Math::BigRat, meaning that
+instead of 2.5 you will get 2+1/2 as output.
+
+=head2 MODULES USED
+
+C<bigrat> is just a thin wrapper around various modules of the Math::BigInt
+family. Think of it as the head of the family, who runs the shop, and orders
+the others to do the work.
+
+The following modules are currently used by bignum:
+
+        Math::BigInt::Lite      (for speed, and only if it is loadable)
+        Math::BigInt
+        Math::BigFloat
+        Math::BigRat
+
+=head2 MATH LIBRARY
+
+Math with the numbers is done (by default) by a module called
+Math::BigInt::Calc. This is equivalent to saying:
+
+       use bigrat lib => 'Calc';
+
+You can change this by using:
+
+       use bigrat lib => 'BitVect';
+
+The following would first try to find Math::BigInt::Foo, then
+Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
+
+       use bigrat lib => 'Foo,Math::BigInt::Bar';
+
+Please see respective module documentation for further details.
+
+=head2 SIGN
+
+The sign is either '+', '-', 'NaN', '+inf' or '-inf' and stored seperately.
+
+A sign of 'NaN' is used to represent the result when input arguments are not
+numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively
+minus infinity. You will get '+inf' when dividing a positive number by 0, and
+'-inf' when dividing any negative number by 0.
+
+=head2 METHODS
+
+Since all numbers are not objects, you can use all functions that are part of
+the BigInt or BigFloat API. It is wise to use only the bxxx() notation, and not
+the fxxx() notation, though. This makes you independed on the fact that the
+underlying object might morph into a different class than BigFloat.
+
+=head1 EXAMPLES
+       perl -Mbigrat -le 'print sqrt(33)'
+       perl -Mbigrat -le 'print 2*255'
+       perl -Mbigrat -le 'print 4.5+2*255'
+       perl -Mbigrat -le 'print 3/7 + 5/7 + 8/3'       
+       perl -Mbigrat -le 'print 12->is_odd()';
+
+=head1 LICENSE
+
+This program is free software; you may redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+Especially L<bignum>.
+
+L<Math::BigFloat>, L<Math::BigInt>, L<Math::BigRat> and L<Math::Big> as well
+as L<Math::BigInt::BitVect>, L<Math::BigInt::Pari> and  L<Math::BigInt::GMP>.
+
+=head1 AUTHORS
+
+(C) by Tels L<http://bloodgate.com/> in early 2002.
+
+=cut