This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Skip some File::Copy tests on Win32 since file permissions do not
[perl5.git] / lib / bigrat.pm
index 8085b74..10e8057 100644 (file)
@@ -1,16 +1,24 @@
 package bigrat;
-require 5.005;
+use 5.006;
 
-$VERSION = '0.08';
+$VERSION = '0.23';
 require Exporter;
-@ISA           = qw( Exporter );
-@EXPORT_OK     = qw( ); 
-@EXPORT                = qw( inf NaN ); 
+@ISA           = qw( bigint );
+@EXPORT_OK     = qw( PI e bpi bexp );
+@EXPORT                = qw( inf NaN );
 
 use strict;
+use overload;
+require bigint;                # no "use" to avoid callind import
 
 ############################################################################## 
 
+BEGIN 
+  {
+  *inf = \&bigint::inf;
+  *NaN = \&bigint::NaN;
+  }
+
 # These are all alike, and thus faked by AUTOLOAD
 
 my @faked = qw/round_mode accuracy precision div_scale/;
@@ -47,16 +55,36 @@ sub AUTOLOAD
   Carp::croak ("Can't call bigrat\-\>$name, not a valid method");
   }
 
-sub upgrade
+sub unimport
   {
-  my $self = shift;
-  no strict 'refs';
-#  if (defined $_[0])
-#    {
-#    $Math::BigInt::upgrade = $_[0];
-#    $Math::BigFloat::upgrade = $_[0];
-#    }
-  return $Math::BigInt::upgrade;
+  $^H{bigrat} = undef;                                 # no longer in effect
+  overload::remove_constant('binary','','float','','integer');
+  }
+
+sub in_effect
+  {
+  my $level = shift || 0;
+  my $hinthash = (caller($level))[10];
+  $hinthash->{bigrat};
+  }
+
+#############################################################################
+# the following two routines are for Perl 5.9.4 or later and are lexical
+
+sub _hex
+  {
+  return CORE::hex($_[0]) unless in_effect(1);
+  my $i = $_[0];
+  $i = '0x'.$i unless $i =~ /^0x/;
+  Math::BigInt->new($i);
+  }
+
+sub _oct
+  {
+  return CORE::oct($_[0]) unless in_effect(1);
+  my $i = $_[0];
+  return Math::BigInt->from_oct($i) if $i =~ /^0[0-7]/;
+  Math::BigInt->new($i);
   }
 
 sub import 
@@ -65,8 +93,17 @@ sub import
 
   # see also bignum->import() for additional comments
 
+  $^H{bigrat} = 1;                                     # we are in effect
+
+  my ($hex,$oct);
+  # for newer Perls always override hex() and oct() with a lexical version:
+  if ($] > 5.009004)
+    {
+    $oct = \&_oct;
+    $hex = \&_hex;
+    }
   # some defaults
-  my $lib = ''; my $upgrade = 'Math::BigFloat';
+  my $lib = ''; my $lib_kind = 'try'; my $upgrade = 'Math::BigFloat';
 
   my @import = ( ':constant' );                                # drive it w/ constant
   my @a = @_; my $l = scalar @_; my $j = 0;
@@ -81,9 +118,10 @@ sub import
       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)$/)
+    elsif ($_[$i] =~ /^(l|lib|try|only)$/)
       {
       # this causes a different low lib to take care...
+      $lib_kind = $1; $lib_kind = 'lib' if $lib_kind eq 'l';
       $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++;
@@ -110,7 +148,17 @@ sub import
       $trace = 1;
       splice @a, $j, 1; $j --;
       }
-    else
+    elsif ($_[$i] eq 'hex')
+      {
+      splice @a, $j, 1; $j --;
+      $hex = \&bigint::_hex_global;
+      }
+    elsif ($_[$i] eq 'oct')
+      {
+      splice @a, $j, 1; $j --;
+      $oct = \&bigint::_oct_global;
+      }
+    elsif ($_[$i] !~ /^(PI|e|bpi|bexp)\z/)
       {
       die ("unknown option $_[$i]");
       }
@@ -138,7 +186,7 @@ sub import
     require Math::BigInt if $_lite == 0;        # not already loaded?
     $class = 'Math::BigInt';                    # regardless of MBIL or not
     }
-  push @import, 'lib' => $lib if $lib ne '';
+  push @import, $lib_kind => $lib if $lib ne ''; 
   # Math::BigInt::Trace or plain Math::BigInt
   $class->import(@import, upgrade => $upgrade);
 
@@ -159,11 +207,35 @@ sub import
     print "Math::BigRat\t\t v$Math::BigRat::VERSION\n";
     exit;
     }
-  $self->export_to_level(1,$self,@a);           # export inf and NaN
+
+  # Take care of octal/hexadecimal constants
+  overload::constant binary => sub { bigint::_binary_constant(shift) };
+
+  # if another big* was already loaded:
+  my ($package) = caller();
+
+  no strict 'refs';
+  if (!defined *{"${package}::inf"})
+    {
+    $self->export_to_level(1,$self,@a);           # export inf and NaN
+    }
+  {
+    no warnings 'redefine';
+    *CORE::GLOBAL::oct = $oct if $oct;
+    *CORE::GLOBAL::hex = $hex if $hex;
+  }
   }
 
-sub inf () { Math::BigInt->binf(); }
-sub NaN () { Math::BigInt->bnan(); }
+sub PI () { Math::BigFloat->new('3.141592653589793238462643383279502884197'); }
+sub e () { Math::BigFloat->new('2.718281828459045235360287471352662497757'); }
+
+sub bpi ($) { local $Math::BigFloat::upgrade; Math::BigFloat::bpi(@_); }
+
+sub bexp ($$)
+  {
+  local $Math::BigFloat::upgrade;
+  my $x = Math::BigFloat->new($_[0]); $x->bexp($_[1]);
+  }
 
 1;
 
@@ -177,12 +249,22 @@ bigrat - Transparent BigNumber/BigRational support for Perl
 
   use bigrat;
 
-  $x = 2 + 4.5,"\n";                   # BigFloat 6.5
+  print 2 + 4.5,"\n";                  # BigFloat 6.5
   print 1/3 + 1/4,"\n";                        # produces 7/12
 
+  {
+    no bigrat;
+    print 1/3,"\n";                    # 0.33333...
+  }
+
+  # Note that this will make hex() and oct() be globally overriden:
+  use bigrat qw/hex oct/;
+  print hex("0x1234567890123490"),"\n";
+  print oct("01234567890123490"),"\n";
+
 =head1 DESCRIPTION
 
-All operators (inlcuding basic math operations) are overloaded. Integer and
+All operators (including basic math operations) are overloaded. Integer and
 floating-point constants are created as proper BigInts or BigFloats,
 respectively.
 
@@ -211,13 +293,23 @@ Math::BigInt::Calc. This is equivalent to saying:
 
 You can change this by using:
 
-       use bigrat lib => 'BitVect';
+        use bignum lib => 'GMP';
 
 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';
 
+Using C<lib> warns if none of the specified libraries can be found and
+L<Math::BigInt> did fall back to one of the default libraries.
+To supress this warning, use C<try> instead:
+
+        use bignum try => 'GMP';
+
+If you want the code to die instead of falling back, use C<only> instead:
+
+        use bignum only => 'GMP';
+
 Please see respective module documentation for further details.
 
 =head2 Sign
@@ -236,6 +328,77 @@ 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.
 
+=over 2
+
+=item inf()
+
+A shortcut to return Math::BigInt->binf(). Useful because Perl does not always
+handle bareword C<inf> properly.
+
+=item NaN()
+
+A shortcut to return Math::BigInt->bnan(). Useful because Perl does not always
+handle bareword C<NaN> properly.
+
+=item e
+
+       # perl -Mbigrat=e -wle 'print e'
+
+Returns Euler's number C<e>, aka exp(1).
+
+=item PI
+
+       # perl -Mbigrat=PI -wle 'print PI'
+
+Returns PI.
+
+=item bexp()
+
+       bexp($power,$accuracy);
+
+
+Returns Euler's number C<e> raised to the appropriate power, to
+the wanted accuracy.
+
+Example:
+
+       # perl -Mbigrat=bexp -wle 'print bexp(1,80)'
+
+=item bpi()
+
+       bpi($accuracy);
+
+Returns PI to the wanted accuracy.
+
+Example:
+
+       # perl -Mbigrat=bpi -wle 'print bpi(80)'
+
+=item upgrade()
+
+Return the class that numbers are upgraded to, is in fact returning
+C<$Math::BigInt::upgrade>.
+
+=item in_effect()
+
+       use bigrat;
+
+       print "in effect\n" if bigrat::in_effect;       # true
+       {
+         no bigrat;
+         print "in effect\n" if bigrat::in_effect;     # false
+       }
+
+Returns true or false if C<bigrat> is in effect in the current scope.
+
+This method only works on Perl v5.9.4 or later.
+
+=back
+
+=head2 MATH LIBRARY
+
+Math with the numbers is done (by default) by a module called
+
 =head2 Cavaet
 
 But a warning is in order. When using the following to make a copy of a number,
@@ -255,7 +418,7 @@ following work:
         print $x + 1, " ", $y,"\n";     # prints 10 9
 
 but calling any method that modifies the number directly will result in
-B<both> the original and the copy beeing destroyed:
+B<both> the original and the copy being destroyed:
 
         $x = 9; $y = $x;
         print $x->badd(1), " ", $y,"\n";        # prints 10 10
@@ -289,6 +452,8 @@ than or equal to zero. See Math::BigInt's bround() function for details.
 
        perl -Mbigrat=a,50 -le 'print sqrt(20)'
 
+Note that setting precision and accurary at the same time is not possible.
+
 =item p or precision
 
 This sets the precision for all math operations. The argument can be any
@@ -298,6 +463,8 @@ integer. See Math::BigInt's bfround() function for details.
 
        perl -Mbigrat=p,-50 -le 'print sqrt(20)'
 
+Note that setting precision and accurary at the same time is not possible.
+
 =item t or trace
 
 This enables a trace mode and is primarily for debugging bignum or
@@ -310,7 +477,23 @@ Load a different math lib, see L<MATH LIBRARY>.
        perl -Mbigrat=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 ;)
+line. This means the following does not work:
+
+       perl -Mbignum=l,GMP,Pari -e 'print 2 ** 512'
+
+This will be hopefully fixed soon ;)
+
+=item hex
+
+Override the built-in hex() method with a version that can handle big
+integers. Note that under Perl v5.9.4 or ealier, this will be global
+and cannot be disabled with "no bigint;".
+
+=item oct
+
+Override the built-in oct() method with a version that can handle big
+integers. Note that under Perl v5.9.4 or ealier, this will be global
+and cannot be disabled with "no bigint;".
 
 =item v or version
 
@@ -318,6 +501,43 @@ This prints out the name and version of all modules used and then exits.
 
        perl -Mbigrat=v
 
+=back
+
+=head1 CAVAETS
+
+=over 2
+
+=item in_effect()
+
+This method only works on Perl v5.9.4 or later.
+
+=item hex()/oct()
+
+C<bigint> overrides these routines with versions that can also handle
+big integer values. Under Perl prior to version v5.9.4, however, this
+will not happen unless you specifically ask for it with the two
+import tags "hex" and "oct" - and then it will be global and cannot be
+disabled inside a scope with "no bigint":
+
+       use bigint qw/hex oct/;
+
+       print hex("0x1234567890123456");
+       {
+               no bigint;
+               print hex("0x1234567890123456");
+       }
+
+The second call to hex() will warn about a non-portable constant.
+
+Compare this to:
+
+       use bigint;
+
+       # will warn only under Perl older than v5.9.4
+       print hex("0x1234567890123456");
+
+=back
+
 =head1 EXAMPLES
  
        perl -Mbigrat -le 'print sqrt(33)'
@@ -325,6 +545,7 @@ This prints out the name and version of all modules used and then exits.
        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()';
+       perl -Mbignum=l,GMP -le 'print 7 ** 7777'
 
 =head1 LICENSE
 
@@ -340,6 +561,6 @@ 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 - 2005.
+(C) by Tels L<http://bloodgate.com/> in early 2002 - 2007.
 
 =cut