Upgrade to prereleases of Math::BigInt 1.70 and
[p5sagit/p5-mst-13.2.git] / lib / Math / BigRat.pm
index 993c2a4..c344e17 100644 (file)
@@ -9,25 +9,27 @@
 #   _n   : numeraotr (value = _n/_d)
 #   _a   : accuracy
 #   _p   : precision
-#   _f   : flags, used by MBR to flag parts of a rationale as untouchable
+#   _f   : flags, used by MBR to flag parts of a rational as untouchable
+# You should not look at the innards of a BigRat - use the methods for this.
 
 package Math::BigRat;
 
 require 5.005_03;
 use strict;
 
-use Exporter;
+require Exporter;
 use Math::BigFloat;
-use vars qw($VERSION @ISA $PACKAGE @EXPORT_OK $upgrade $downgrade
+use vars qw($VERSION @ISA $PACKAGE $upgrade $downgrade
             $accuracy $precision $round_mode $div_scale $_trap_nan $_trap_inf);
 
 @ISA = qw(Exporter Math::BigFloat);
-@EXPORT_OK = qw();
 
-$VERSION = '0.10';
+$VERSION = '0.12';
 
 use overload;                  # inherit from Math::BigFloat
 
+BEGIN { *objectify = \&Math::BigInt::objectify; }
+
 ##############################################################################
 # global constants, flags and accessory
 
@@ -45,8 +47,10 @@ $_trap_nan = 0;                         # are NaNs ok? set w/ config()
 $_trap_inf = 0;                         # are infs ok? set w/ config()
 
 my $nan = 'NaN';
-my $class = 'Math::BigRat';
 my $MBI = 'Math::BigInt';
+my $CALC = 'Math::BigInt::Calc';
+my $class = 'Math::BigRat';
+my $IMPORT = 0;
 
 sub isa
   {
@@ -54,28 +58,36 @@ sub isa
   UNIVERSAL::isa(@_);
   }
 
+sub BEGIN
+  {
+  *AUTOLOAD = \&Math::BigFloat::AUTOLOAD;
+  }
+
 sub _new_from_float
   {
-  # turn a single float input into a rationale (like '0.1')
+  # turn a single float input into a rational number (like '0.1')
   my ($self,$f) = @_;
 
   return $self->bnan() if $f->is_nan();
-  return $self->binf('-inf') if $f->{sign} eq '-inf';
-  return $self->binf('+inf') if $f->{sign} eq '+inf';
+  return $self->binf($f->{sign}) if $f->{sign} =~ /^[+-]inf$/;
 
-  $self->{_n} = $f->{_m}->copy();                      # mantissa
+  local $Math::BigInt::accuracy = undef;
+  local $Math::BigInt::precision = undef;
+  $self->{_n} = $MBI->new($CALC->_str ( $f->{_m} ),undef,undef);# mantissa
   $self->{_d} = $MBI->bone();
-  $self->{sign} = $f->{sign} || '+'; $self->{_n}->{sign} = '+';
-  if ($f->{_e}->{sign} eq '-')
+  $self->{sign} = $f->{sign} || '+';
+  if ($f->{_es} eq '-')
     {
     # something like Math::BigRat->new('0.1');
-    $self->{_d}->blsft($f->{_e}->copy()->babs(),10);   # 1 / 1 => 1/10
+    # 1 / 1 => 1/10
+    $self->{_d}->blsft( $MBI->new($CALC->_str ( $f->{_e} )),10);       
     }
   else
     {
     # something like Math::BigRat->new('10');
     # 1 / 1 => 10/1
-    $self->{_n}->blsft($f->{_e},10) unless $f->{_e}->is_zero();        
+    $self->{_n}->blsft( $MBI->new($CALC->_str($f->{_e})),10) unless 
+      $CALC->_is_zero($f->{_e});       
     }
   $self;
   }
@@ -95,7 +107,7 @@ sub new
     {
     if ($n->isa('Math::BigFloat'))
       {
-      return $self->_new_from_float($n)->bnorm();
+      $self->_new_from_float($n);
       }
     if ($n->isa('Math::BigInt'))
       {
@@ -103,7 +115,6 @@ sub new
       $self->{_n} = $n->copy();                                # "mantissa" = $n
       $self->{_d} = $MBI->bone();
       $self->{sign} = $self->{_n}->{sign}; $self->{_n}->{sign} = '+';
-      return $self->bnorm();
       }
     if ($n->isa('Math::BigInt::Lite'))
       {
@@ -111,8 +122,8 @@ sub new
       $self->{sign} = '+'; $self->{sign} = '-' if $$n < 0;
       $self->{_n} = $MBI->new(abs($$n),undef,undef);   # "mantissa" = $n
       $self->{_d} = $MBI->bone();
-      return $self->bnorm();
       }
+    return $self->bnorm();
     }
   return $n->copy() if ref $n;
 
@@ -138,17 +149,19 @@ sub new
       local $Math::BigFloat::precision = undef;
       local $Math::BigInt::accuracy = undef;
       local $Math::BigInt::precision = undef;
-      my $nf = Math::BigFloat->new($n);
+
+      my $nf = Math::BigFloat->new($n,undef,undef);
       $self->{sign} = '+';
       return $self->bnan() if $nf->is_nan();
-      $self->{_n} = $nf->{_m};
+      $self->{_n} = $MBI->new( $CALC->_str( $nf->{_m} ) );
+
       # now correct $self->{_n} due to $n
       my $f = Math::BigFloat->new($d,undef,undef);
-      $self->{_d} = $f->{_m};
       return $self->bnan() if $f->is_nan();
-      #print "n=$nf e$nf->{_e} d=$f e$f->{_e}\n";
+      $self->{_d} = $MBI->new( $CALC->_str( $f->{_m} ) );
+
       # calculate the difference between nE and dE
-      my $diff_e = $nf->{_e}->copy()->bsub ( $f->{_e} );
+      my $diff_e = $MBI->new ($nf->exponent())->bsub ( $f->exponent);
       if ($diff_e->is_negative())
        {
         # < 0: mul d with it
@@ -174,8 +187,13 @@ sub new
         # inf/inf => NaN
         return $self->bnan() if
          ($self->{_n}->is_inf() && $self->{_d}->is_inf());
-        # +-inf/123 => +-inf
-        return $self->binf($self->{sign}) if $self->{_n}->is_inf();
+        if ($self->{_n}->is_inf())
+         {
+         my $s = '+';          # '+inf/+123' or '-inf/-123'
+         $s = '-' if substr($self->{_n}->{sign},0,1) ne $self->{_d}->{sign};
+         # +-inf/123 => +-inf
+          return $self->binf($s);
+         }
         # 123/inf => 0
         return $self->bzero();
         }
@@ -212,6 +230,31 @@ sub new
   $self->bnorm();
   }
 
+sub copy
+  {
+  my ($c,$x);
+  if (@_ > 1)
+    {
+    # if two arguments, the first one is the class to "swallow" subclasses
+    ($c,$x) = @_;
+    }
+  else
+    {
+    $x = shift;
+    $c = ref($x);
+    }
+  return unless ref($x); # only for objects
+
+  my $self = {}; bless $self,$c;
+
+  $self->{sign} = $x->{sign};
+  $self->{_d} = $x->{_d}->copy();
+  $self->{_n} = $x->{_n}->copy();
+  $self->{_a} = $x->{_a} if defined $x->{_a};
+  $self->{_p} = $x->{_p} if defined $x->{_p};
+  $self;
+  }
+
 ##############################################################################
 
 sub config
@@ -231,7 +274,7 @@ sub config
 
 sub bstr
   {
-  my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
 
   if ($x->{sign} !~ /^[+-]$/)          # inf, NaN etc
     {
@@ -239,10 +282,10 @@ sub bstr
     return $s;
     }
 
-  my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';    # +3 vs 3
+  my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';    # '+3/2' => '3/2'
 
-  return $s.$x->{_n}->bstr() if $x->{_d}->is_one(); 
-  return $s.$x->{_n}->bstr() . '/' . $x->{_d}->bstr(); 
+  return $s . $x->{_n}->bstr() if $x->{_d}->is_one();
+  $s . $x->{_n}->bstr() . '/' . $x->{_d}->bstr();
   }
 
 sub bsstr
@@ -256,7 +299,7 @@ sub bsstr
     }
   
   my $s = ''; $s = $x->{sign} if $x->{sign} ne '+';    # +3 vs 3
-  return $s . $x->{_n}->bstr() . '/' . $x->{_d}->bstr(); 
+  $s . $x->{_n}->bstr() . '/' . $x->{_d}->bstr(); 
   }
 
 sub bnorm
@@ -279,8 +322,8 @@ sub bnorm
   $x->{_d}->{_f} = MB_NEVER_ROUND;
   $x->{_n}->{_f} = MB_NEVER_ROUND;
   # 'forget' that parts were rounded via MBI::bround() in MBF's bfround()
-  $x->{_d}->{_a} = undef; $x->{_n}->{_a} = undef;
-  $x->{_d}->{_p} = undef; $x->{_n}->{_p} = undef; 
+  delete $x->{_d}->{_a}; delete $x->{_n}->{_a};
+  delete $x->{_d}->{_p}; delete $x->{_n}->{_p}; 
 
   # no normalize for NaN, inf etc.
   return $x if $x->{sign} !~ /^[+-]$/;
@@ -365,7 +408,7 @@ sub _bzero
 
 sub badd
   {
-  # add two rationales
+  # add two rational numbers
 
   # set up parameters
   my ($self,$x,$y,@r) = (ref($_[0]),@_);
@@ -402,7 +445,7 @@ sub badd
 
   $x->{_d}->bmul($y->{_d});
 
-  # calculate new sign
+  # calculate sign of result and norm our _n part
   $x->{sign} = $x->{_n}->{sign}; $x->{_n}->{sign} = '+';
 
   $x->bnorm()->round(@r);
@@ -410,7 +453,7 @@ sub badd
 
 sub bsub
   {
-  # subtract two rationales
+  # subtract two rational numbers
 
   # set up parameters
   my ($self,$x,$y,@r) = (ref($_[0]),@_);
@@ -420,41 +463,18 @@ sub bsub
     ($self,$x,$y,@r) = objectify(2,@_);
     }
 
-  # TODO: $self instead or $class??
-  $x = $class->new($x) unless $x->isa($class);
-  $y = $class->new($y) unless $y->isa($class);
-
-  return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
-  # TODO: inf handling
-
-  #  1   1    gcd(3,4) = 1    1*3 - 1*4    7
-  #  - - -                  = --------- = --                 
-  #  4   3                      4*3       12
-  
-  # we do not compute the gcd() here, but simple do:
-  #  5   7    5*3 - 7*4     13
-  #  - - -  = --------- = - --
-  #  4   3       4*3        12
-
-  local $Math::BigInt::accuracy = undef;
-  local $Math::BigInt::precision = undef;
-
-  $x->{_n}->bmul($y->{_d}); $x->{_n}->{sign} = $x->{sign};
-  my $m = $y->{_n}->copy()->bmul($x->{_d});
-  $m->{sign} = $y->{sign};                     # 2/1 - 2/1
-  $x->{_n}->bsub($m);
-
-  $x->{_d}->bmul($y->{_d});
-  
-  # calculate new sign
-  $x->{sign} = $x->{_n}->{sign}; $x->{_n}->{sign} = '+';
-
-  $x->bnorm()->round(@r);
+  # flip sign of $x, call badd(), then flip sign of result
+  $x->{sign} =~ tr/+-/-+/
+    unless $x->{sign} eq '+' && $x->{_n}->is_zero();   # not -0
+  $x->badd($y,@r);                     # does norm and round
+  $x->{sign} =~ tr/+-/-+/ 
+    unless $x->{sign} eq '+' && $x->{_n}->is_zero();   # not -0
+  $x;
   }
 
 sub bmul
   {
-  # multiply two rationales
+  # multiply two rational numbers
   
   # set up parameters
   my ($self,$x,$y,@r) = (ref($_[0]),@_);
@@ -464,9 +484,8 @@ sub bmul
     ($self,$x,$y,@r) = objectify(2,@_);
     }
 
-  # TODO: $self instead or $class??
-  $x = $class->new($x) unless $x->isa($class);
-  $y = $class->new($y) unless $y->isa($class);
+  $x = $self->new($x) unless $x->isa($self);
+  $y = $self->new($y) unless $y->isa($self);
 
   return $x->bnan() if ($x->{sign} eq 'NaN' || $y->{sign} eq 'NaN');
 
@@ -516,9 +535,8 @@ sub bdiv
     ($self,$x,$y,@r) = objectify(2,@_);
     }
 
-  # TODO: $self instead or $class??
-  $x = $class->new($x) unless $x->isa($class);
-  $y = $class->new($y) unless $y->isa($class);
+  $x = $self->new($x) unless $x->isa($self);
+  $y = $self->new($y) unless $y->isa($self);
 
   return $self->_div_inf($x,$y)
    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
@@ -532,8 +550,8 @@ sub bdiv
   # -  /  - == - * -
   # 4     3    4   1
   
-#  local $Math::BigInt::accuracy = undef;
-#  local $Math::BigInt::precision = undef;
+  local $Math::BigInt::accuracy = undef;
+  local $Math::BigInt::precision = undef;
   $x->{_n}->bmul($y->{_d});
   $x->{_d}->bmul($y->{_n});
 
@@ -556,9 +574,8 @@ sub bmod
     ($self,$x,$y,@r) = objectify(2,@_);
     }
 
-  # TODO: $self instead or $class??
-  $x = $class->new($x) unless $x->isa($class);
-  $y = $class->new($y) unless $y->isa($class);
+  $x = $self->new($x) unless $x->isa($self);
+  $y = $self->new($y) unless $y->isa($self);
 
   return $self->_div_inf($x,$y)
    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
@@ -610,6 +627,8 @@ sub bdec
 
   return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
 
+  local $Math::BigInt::accuracy = undef;
+  local $Math::BigInt::precision = undef;
   if ($x->{sign} eq '-')
     {
     $x->{_n}->badd($x->{_d});  # -5/2 => -7/2
@@ -637,6 +656,8 @@ sub binc
   
   return $x if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf
 
+  local $Math::BigInt::accuracy = undef;
+  local $Math::BigInt::precision = undef;
   if ($x->{sign} eq '-')
     {
     if ($x->{_n}->bacmp($x->{_d}) < 0)
@@ -663,7 +684,7 @@ sub binc
 sub is_int
   {
   # return true if arg (BRAT or num_str) is an integer
-  my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
 
   return 1 if ($x->{sign} =~ /^[+-]$/) &&      # NaN and +-inf aren't
     $x->{_d}->is_one();                                # x/y && y != 1 => no integer
@@ -673,7 +694,7 @@ sub is_int
 sub is_zero
   {
   # return true if arg (BRAT or num_str) is zero
-  my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
 
   return 1 if $x->{sign} eq '+' && $x->{_n}->is_zero();
   0;
@@ -682,9 +703,9 @@ sub is_zero
 sub is_one
   {
   # return true if arg (BRAT or num_str) is +1 or -1 if signis given
-  my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
 
-  my $sign = shift || ''; $sign = '+' if $sign ne '-';
+  my $sign = $_[2] || ''; $sign = '+' if $sign ne '-';
   return 1
    if ($x->{sign} eq $sign && $x->{_n}->is_one() && $x->{_d}->is_one());
   0;
@@ -693,7 +714,7 @@ sub is_one
 sub is_odd
   {
   # return true if arg (BFLOAT or num_str) is odd or false if even
-  my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
 
   return 1 if ($x->{sign} =~ /^[+-]$/) &&              # NaN & +-inf aren't
     ($x->{_d}->is_one() && $x->{_n}->is_odd());                # x/2 is not, but 3/1
@@ -703,7 +724,7 @@ sub is_odd
 sub is_even
   {
   # return true if arg (BINT or num_str) is even or false if odd
-  my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
 
   return 0 if $x->{sign} !~ /^[+-]$/;                  # NaN & +-inf aren't
   return 1 if ($x->{_d}->is_one()                      # x/3 is never
@@ -711,11 +732,6 @@ sub is_even
   0;
   }
 
-BEGIN
-  {
-  *objectify = \&Math::BigInt::objectify;
-  }
-
 ##############################################################################
 # parts() and friends
 
@@ -752,12 +768,18 @@ sub parts
 
 sub length
   {
-  return 0;
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
+
+  return $nan unless $x->is_int();
+  $x->{_n}->length();                  # length(-123/1) => length(123)
   }
 
 sub digit
   {
-  return 0;
+  my ($self,$x,$n) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
+
+  return $nan unless $x->is_int();
+  $x->{_n}->digit($n);                 # digit(-123/1,2) => digit(123,2)
   }
 
 ##############################################################################
@@ -800,6 +822,7 @@ sub bfac
   {
   my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
 
+  # if $x is an integer
   if (($x->{sign} eq '+') && ($x->{_d}->is_one()))
     {
     $x->{_n}->bfac();
@@ -890,7 +913,105 @@ sub bpow
 
 sub blog
   {
-  return Math::BigRat->bnan();
+  # set up parameters
+  my ($self,$x,$y,@r) = (ref($_[0]),@_);
+
+  # objectify is costly, so avoid it
+  if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+    {
+    ($self,$x,$y,@r) = objectify(2,$class,@_);
+    }
+
+  # blog(1,Y) => 0
+  return $x->bzero() if $x->is_one() && $y->{sign} eq '+';
+
+  # $x <= 0 => NaN
+  return $x->bnan() if $x->is_zero() || $x->{sign} ne '+' || $y->{sign} ne '+';
+
+  if ($x->is_int() && $y->is_int())
+    {
+    return $self->new($x->as_number()->blog($y->as_number(),@r));
+    }
+
+  # do it with floats
+  $x->_new_from_float( $x->_as_float()->blog(Math::BigFloat->new("$y"),@r) );
+  }
+
+sub _as_float
+  {
+  my $x = shift;
+
+  local $Math::BigFloat::upgrade = undef;
+  local $Math::BigFloat::accuracy = undef;
+  local $Math::BigFloat::precision = undef;
+  # 22/7 => 3.142857143..
+  Math::BigFloat->new($x->{_n})->bdiv($x->{_d}, $x->accuracy());
+  }
+
+sub broot
+  {
+  # set up parameters
+  my ($self,$x,$y,@r) = (ref($_[0]),@_);
+  # objectify is costly, so avoid it
+  if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+    {
+    ($self,$x,$y,@r) = objectify(2,@_);
+    }
+
+  if ($x->is_int() && $y->is_int())
+    {
+    return $self->new($x->as_number()->broot($y->as_number(),@r));
+    }
+
+  # do it with floats
+  $x->_new_from_float( $x->_as_float()->broot($y,@r) );
+  }
+
+sub bmodpow
+  {
+  # set up parameters
+  my ($self,$x,$y,$m,@r) = (ref($_[0]),@_);
+  # objectify is costly, so avoid it
+  if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+    {
+    ($self,$x,$y,$m,@r) = objectify(3,@_);
+    }
+
+  # $x or $y or $m are NaN or +-inf => NaN
+  return $x->bnan()
+   if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/ ||
+   $m->{sign} !~ /^[+-]$/;
+
+  if ($x->is_int() && $y->is_int() && $m->is_int())
+    {
+    return $self->new($x->as_number()->bmodpow($y->as_number(),$m,@r));
+    }
+
+  warn ("bmodpow() not fully implemented");
+  $x->bnan();
+  }
+
+sub bmodinv
+  {
+  # set up parameters
+  my ($self,$x,$y,@r) = (ref($_[0]),@_);
+  # objectify is costly, so avoid it
+  if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+    {
+    ($self,$x,$y,@r) = objectify(2,@_);
+    }
+
+  # $x or $y are NaN or +-inf => NaN
+  return $x->bnan() 
+   if $x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/;
+
+  if ($x->is_int() && $y->is_int())
+    {
+    return $self->new($x->as_number()->bmodinv($y->as_number(),@r));
+    }
+
+  warn ("bmodinv() not fully implemented");
+  $x->bnan();
   }
 
 sub bsqrt
@@ -908,41 +1029,46 @@ sub bsqrt
   local $Math::BigInt::upgrade = undef;
   local $Math::BigInt::precision = undef;
   local $Math::BigInt::accuracy = undef;
+
   $x->{_d} = Math::BigFloat->new($x->{_d})->bsqrt();
   $x->{_n} = Math::BigFloat->new($x->{_n})->bsqrt();
 
   # if sqrt(D) was not integer
-  if ($x->{_d}->{_e}->{sign} ne '+')
+  if ($x->{_d}->{_es} ne '+')
     {
-    $x->{_n}->blsft($x->{_d}->{_e}->babs(),10);                # 7.1/4.51 => 7.1/45.1
-    $x->{_d} = $x->{_d}->{_m};                         # 7.1/45.1 => 71/45.1
+    $x->{_n}->blsft($x->{_d}->exponent()->babs(),10);  # 7.1/4.51 => 7.1/45.1
+    $x->{_d} = $MBI->new($CALC->_str($x->{_d}->{_m})); # 7.1/45.1 => 71/45.1
     }
   # if sqrt(N) was not integer
-  if ($x->{_n}->{_e}->{sign} ne '+')
+  if ($x->{_n}->{_es} ne '+')
     {
-    $x->{_d}->blsft($x->{_n}->{_e}->babs(),10);                # 71/45.1 => 710/45.1
-    $x->{_n} = $x->{_n}->{_m};                         # 710/45.1 => 710/451
+    $x->{_d}->blsft($x->{_n}->exponent()->babs(),10);  # 71/45.1 => 710/45.1
+    $x->{_n} = $MBI->new($CALC->_str($x->{_n}->{_m})); # 710/45.1 => 710/451
     }
  
   # convert parts to $MBI again 
-  $x->{_n} = $x->{_n}->as_number();
-  $x->{_d} = $x->{_d}->as_number();
+  $x->{_n} = $x->{_n}->as_number() unless $x->{_n}->isa($MBI);
+  $x->{_d} = $x->{_d}->as_number() unless $x->{_d}->isa($MBI);
   $x->bnorm()->round(@r);
   }
 
 sub blsft
   {
-  my ($self,$x,$y,$b,$a,$p,$r) = objectify(3,@_);
+  my ($self,$x,$y,$b,@r) = objectify(3,@_);
  
-  $x->bmul( $b->copy()->bpow($y), $a,$p,$r);
+  $b = 2 unless defined $b;
+  $b = $self->new($b) unless ref ($b);
+  $x->bmul( $b->copy()->bpow($y), @r);
   $x;
   }
 
 sub brsft
   {
-  my ($self,$x,$y,$b,$a,$p,$r) = objectify(2,@_);
+  my ($self,$x,$y,$b,@r) = objectify(2,@_);
 
-  $x->bdiv( $b->copy()->bpow($y), $a,$p,$r);
+  $b = 2 unless defined $b;
+  $b = $self->new($b) unless ref ($b);
+  $x->bdiv( $b->copy()->bpow($y), @r);
   $x;
   }
 
@@ -969,7 +1095,15 @@ sub bfround
 
 sub bcmp
   {
-  my ($self,$x,$y) = objectify(2,@_);
+  # compare two signed numbers 
+  
+  # set up parameters
+  my ($self,$x,$y) = (ref($_[0]),@_);
+  # objectify is costly, so avoid it
+  if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+    {
+    ($self,$x,$y) = objectify(2,@_);
+    }
 
   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
     {
@@ -999,14 +1133,23 @@ sub bcmp
 
 sub bacmp
   {
-  my ($self,$x,$y) = objectify(2,@_);
+  # compare two numbers (as unsigned)
+  # set up parameters
+  my ($self,$x,$y) = (ref($_[0]),@_);
+  # objectify is costly, so avoid it
+  if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+    {
+    ($self,$x,$y) = objectify(2,$class,@_);
+    }
 
   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
     {
     # handle +-inf and NaN
     return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
     return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
-    return +1;  # inf is always bigger
+    return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
+    return -1;
     }
 
   my $t = $x->{_n} * $y->{_d};
@@ -1034,7 +1177,7 @@ sub numify
 
 sub as_number
   {
-  my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
 
   return $x if $x->{sign} !~ /^[+-]$/;                 # NaN, inf etc
  
@@ -1047,11 +1190,33 @@ sub as_number
   $t;
   }
 
+sub as_bin
+  {
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
+
+  return $x unless $x->is_int();
+
+  my $s = $x->{sign}; $s = '' if $s eq '+';
+  $s . $x->{_n}->as_bin();
+  }
+
+sub as_hex
+  {
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
+
+  return $x unless $x->is_int();
+
+  my $s = $x->{sign}; $s = '' if $s eq '+';
+  $s . $x->{_n}->as_hex();
+  }
+
 sub import
   {
   my $self = shift;
   my $l = scalar @_;
   my $lib = ''; my @a;
+  $IMPORT++;
+
   for ( my $i = 0; $i < $l ; $i++)
     {
 #    print "at $_[$i] (",$_[$i+1]||'undef',")\n";
@@ -1088,7 +1253,7 @@ sub import
       push @a, $_[$i];
       }
     }
-  # let use Math::BigInt lib => 'GMP'; use Math::BigFloat; still work
+  # let use Math::BigInt lib => 'GMP'; use Math::BigRat; still work
   my $mbilib = eval { Math::BigInt->config()->{lib} };
   if ((defined $mbilib) && ($MBI eq 'Math::BigInt'))
     {
@@ -1120,6 +1285,8 @@ sub import
     require Carp; Carp::croak ("Couldn't load $MBI: $! $@");
     }
 
+  $CALC = Math::BigFloat->config()->{lib};
+  
   # any non :constant stuff is handled by our parent, Exporter
   # even if @_ is empty, to give it a chance
   $self->SUPER::import(@a);             # for subclasses
@@ -1132,21 +1299,26 @@ __END__
 
 =head1 NAME
 
-Math::BigRat - arbitrarily big rationales
+Math::BigRat - arbitrarily big rational numbers
 
 =head1 SYNOPSIS
 
        use Math::BigRat;
 
-       $x = Math::BigRat->new('3/7'); $x += '5/9';
+       my $x = Math::BigRat->new('3/7'); $x += '5/9';
 
        print $x->bstr(),"\n";
        print $x ** 2,"\n";
 
+       my $y = Math::BigRat->new('inf');
+       print "$y ", ($y->is_inf ? 'is' : 'is not') , " infinity\n";
+
+       my $z = Math::BigRat->new(144); $z->bsqrt();
+
 =head1 DESCRIPTION
 
 Math::BigRat complements Math::BigInt and Math::BigFloat by providing support
-for arbitrarily big rationales.
+for arbitrarily big rational numbers.
 
 =head2 MATH LIBRARY
 
@@ -1191,6 +1363,7 @@ information.
 Create a new Math::BigRat object. Input can come in various forms:
 
        $x = Math::BigRat->new(123);                            # scalars
+       $x = Math::BigRat->new('inf');                          # infinity
        $x = Math::BigRat->new('123.3');                        # float
        $x = Math::BigRat->new('1/3');                          # simple string
        $x = Math::BigRat->new('1 / 3');                        # spaced
@@ -1311,6 +1484,12 @@ and then increment it by one).
 
 Truncate $x to an integer value.
 
+=head2 bsqrt()
+       
+       $x->bsqrt();
+
+Calculate the square root of $x.
+
 =head2 config
 
         use Data::Dumper;
@@ -1368,6 +1547,8 @@ Some things are not yet implemented, or only implemented half-way:
 
 =item $x ** $y where $y is not an integer
 
+=item bmod(), blog(), bmodinv() and bmodpow() (partial)
+
 =back
 
 =head1 LICENSE
@@ -1388,6 +1569,6 @@ may contain more documentation and examples as well as testcases.
 
 =head1 AUTHORS
 
-(C) by Tels L<http://bloodgate.com/> 2001-2002. 
+(C) by Tels L<http://bloodgate.com/> 2001, 2002, 2003, 2004.
 
 =cut