This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Comply with the 0x80th commandment
[perl5.git] / lib / Math / BigInt.pm
index 9a26f33..758d7d8 100644 (file)
@@ -18,10 +18,11 @@ package Math::BigInt;
 my $class = "Math::BigInt";
 require 5.005;
 
-$VERSION = '1.68';
-use Exporter;
-@ISA =       qw( Exporter );
-@EXPORT_OK = qw( objectify bgcd blcm); 
+$VERSION = '1.77';
+
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(objectify bgcd blcm); 
+
 # _trap_inf and _trap_nan are internal and should never be accessed from the
 # outside
 use vars qw/$round_mode $accuracy $precision $div_scale $rnd_mode 
@@ -53,14 +54,18 @@ use overload
 '^='   =>      sub { $_[0]->bxor($_[1]); },
 '&='   =>      sub { $_[0]->band($_[1]); },
 '|='   =>      sub { $_[0]->bior($_[1]); },
+
 '**='  =>      sub { $_[0]->bpow($_[1]); },
+'<<='  =>      sub { $_[0]->blsft($_[1]); },
+'>>='  =>      sub { $_[0]->brsft($_[1]); },
 
 # not supported by Perl yet
 '..'   =>      \&_pointpoint,
 
+# we might need '==' and '!=' to get things like "NaN == NaN" right
 '<=>'  =>      sub { $_[2] ?
                       ref($_[0])->bcmp($_[1],$_[0]) : 
-                      $_[0]->bcmp($_[1])},
+                      $_[0]->bcmp($_[1])},
 'cmp'  =>      sub {
          $_[2] ? 
                "$_[1]" cmp $_[0]->bstr() :
@@ -70,7 +75,13 @@ use overload
 'cos'  =>      sub { cos($_[0]->numify()) }, 
 'sin'  =>      sub { sin($_[0]->numify()) }, 
 'exp'  =>      sub { exp($_[0]->numify()) }, 
-'atan2'        =>      sub { atan2($_[0]->numify(),$_[1]) }, 
+'atan2'        =>      sub { $_[2] ?
+                       atan2($_[1],$_[0]->numify()) :
+                       atan2($_[0]->numify(),$_[1]) },
+
+# are not yet overloadable
+#'hex' =>      sub { print "hex"; $_[0]; }, 
+#'oct' =>      sub { print "oct"; $_[0]; }, 
 
 'log'  =>      sub { $_[0]->copy()->blog($_[1]); }, 
 'int'  =>      sub { $_[0]->copy(); }, 
@@ -79,10 +90,10 @@ use overload
 'sqrt'  =>     sub { $_[0]->copy()->bsqrt(); },
 '~'    =>      sub { $_[0]->copy()->bnot(); },
 
-# for sub it is a bit tricky to keep b: b-a => -a+b
+# for subtract it's a bit tricky to not modify b: b-a => -a+b
 '-'    =>      sub { my $c = $_[0]->copy; $_[2] ?
-                   $c->bneg()->badd($_[1]) :
-                   $c->bsub( $_[1]) },
+                       $c->bneg()->badd( $_[1]) :
+                       $c->bsub( $_[1]) },
 '+'    =>      sub { $_[0]->copy()->badd($_[1]); },
 '*'    =>      sub { $_[0]->copy()->bmul($_[1]); },
 
@@ -134,8 +145,8 @@ use overload
 ##############################################################################
 # global constants, flags and accessory
 
-# these are public, but their usage is not recommended, use the accessor
-# methods instead
+# These vars are public, but their direct usage is not recommended, use the
+# accessor methods instead
 
 $round_mode = 'even'; # one of 'even', 'odd', '+inf', '-inf', 'zero' or 'trunc'
 $accuracy   = undef;
@@ -145,22 +156,20 @@ $div_scale  = 40;
 $upgrade = undef;                      # default is no upgrade
 $downgrade = undef;                    # default is no downgrade
 
-# these are internally, and not to be used from the outside
-
-sub MB_NEVER_ROUND () { 0x0001; }
+# These are internally, and not to be used from the outside at all
 
 $_trap_nan = 0;                                # are NaNs ok? set w/ config()
 $_trap_inf = 0;                                # are infs ok? set w/ config()
 my $nan = 'NaN';                       # constants for easier life
 
-my $CALC = 'Math::BigInt::Calc';       # module to do the low level math
-                                       # default is Calc.pm
-my %CAN;                               # cache for $CALC->can(...)
+my $CALC = 'Math::BigInt::FastCalc';   # module to do the low level math
+                                       # default is FastCalc.pm
 my $IMPORT = 0;                                # was import() called yet?
                                        # used to make require work
-
+my %WARN;                              # warn only once for low-level libs
+my %CAN;                               # cache for $CALC->can(...)
+my %CALLBACKS;                         # callbacks to notify on lib loads
 my $EMU_LIB = 'Math/BigInt/CalcEmu.pm';        # emulate low-level math
-my $EMU = 'Math::BigInt::CalcEmu';     # emulate low-level math
 
 ##############################################################################
 # the old code had $rnd_mode, so we need to support it, too
@@ -210,8 +219,7 @@ sub upgrade
   # need to set new value?
   if (@_ > 0)
     {
-    my $u = shift;
-    return ${"${class}::upgrade"} = $u;
+    return ${"${class}::upgrade"} = $_[0];
     }
   ${"${class}::upgrade"};
   }
@@ -225,8 +233,7 @@ sub downgrade
   # need to set new value?
   if (@_ > 0)
     {
-    my $u = shift;
-    return ${"${class}::downgrade"} = $u;
+    return ${"${class}::downgrade"} = $_[0];
     }
   ${"${class}::downgrade"};
   }
@@ -243,7 +250,7 @@ sub div_scale
       {
       require Carp; Carp::croak ('div_scale must be greater than zero');
       }
-    ${"${class}::div_scale"} = shift;
+    ${"${class}::div_scale"} = $_[0];
     }
   ${"${class}::div_scale"};
   }
@@ -284,26 +291,25 @@ sub accuracy
     if (ref($x))
       {
       # $object->accuracy() or fallback to global
-      $x->bround($a) if $a;             # not for undef, 0
-      $x->{_a} = $a;                    # set/overwrite, even if not rounded
-      $x->{_p} = undef;                 # clear P
+      $x->bround($a) if $a;            # not for undef, 0
+      $x->{_a} = $a;                   # set/overwrite, even if not rounded
+      delete $x->{_p};                 # clear P
       $a = ${"${class}::accuracy"} unless defined $a;   # proper return value
       }
     else
       {
-      # set global
-      ${"${class}::accuracy"} = $a;
-      ${"${class}::precision"} = undef; # clear P
+      ${"${class}::accuracy"} = $a;    # set global A
+      ${"${class}::precision"} = undef;        # clear global P
       }
-    return $a;                          # shortcut
+    return $a;                         # shortcut
     }
 
-  my $r;
+  my $a;
   # $object->accuracy() or fallback to global
-  $r = $x->{_a} if ref($x);
+  $a = $x->{_a} if ref($x);
   # but don't return global undef, when $x's accuracy is 0!
-  $r = ${"${class}::accuracy"} if !defined $r;
-  $r;
+  $a = ${"${class}::accuracy"} if !defined $a;
+  $a;
   }
 
 sub precision
@@ -331,26 +337,25 @@ sub precision
     if (ref($x))
       {
       # $object->precision() or fallback to global
-      $x->bfround($p) if $p;            # not for undef, 0
-      $x->{_p} = $p;                    # set/overwrite, even if not rounded
-      $x->{_a} = undef;                 # clear A
+      $x->bfround($p) if $p;           # not for undef, 0
+      $x->{_p} = $p;                   # set/overwrite, even if not rounded
+      delete $x->{_a};                 # clear A
       $p = ${"${class}::precision"} unless defined $p;  # proper return value
       }
     else
       {
-      # set global
-      ${"${class}::precision"} = $p;
-      ${"${class}::accuracy"} = undef;  # clear A
+      ${"${class}::precision"} = $p;   # set global P
+      ${"${class}::accuracy"} = undef; # clear global A
       }
-    return $p;                          # shortcut
+    return $p;                         # shortcut
     }
 
-  my $r;
+  my $p;
   # $object->precision() or fallback to global
-  $r = $x->{_p} if ref($x);
+  $p = $x->{_p} if ref($x);
   # but don't return global undef, when $x's precision is 0!
-  $r = ${"${class}::precision"} if !defined $r;
-  $r;
+  $p = ${"${class}::precision"} if !defined $p;
+  $p;
   }
 
 sub config
@@ -419,22 +424,34 @@ sub _scale_a
   { 
   # select accuracy parameter based on precedence,
   # used by bround() and bfround(), may return undef for scale (means no op)
-  my ($x,$s,$m,$scale,$mode) = @_;
-  $scale = $x->{_a} if !defined $scale;
-  $scale = $s if (!defined $scale);
-  $mode = $m if !defined $mode;
-  return ($scale,$mode);
+  my ($x,$scale,$mode) = @_;
+
+  $scale = $x->{_a} unless defined $scale;
+
+  no strict 'refs';
+  my $class = ref($x);
+
+  $scale = ${ $class . '::accuracy' } unless defined $scale;
+  $mode = ${ $class . '::round_mode' } unless defined $mode;
+
+  ($scale,$mode);
   }
 
 sub _scale_p
   { 
   # select precision parameter based on precedence,
   # used by bround() and bfround(), may return undef for scale (means no op)
-  my ($x,$s,$m,$scale,$mode) = @_;
-  $scale = $x->{_p} if !defined $scale;
-  $scale = $s if (!defined $scale);
-  $mode = $m if !defined $mode;
-  return ($scale,$mode);
+  my ($x,$scale,$mode) = @_;
+  
+  $scale = $x->{_p} unless defined $scale;
+
+  no strict 'refs';
+  my $class = ref($x);
+
+  $scale = ${ $class . '::precision' } unless defined $scale;
+  $mode = ${ $class . '::round_mode' } unless defined $mode;
+
+  ($scale,$mode);
   }
 
 ##############################################################################
@@ -455,47 +472,12 @@ sub copy
     }
   return unless ref($x); # only for objects
 
-  my $self = {}; bless $self,$c;
-  my $r;
-  foreach my $k (keys %$x)
-    {
-    if ($k eq 'value')
-      {
-      $self->{value} = $CALC->_copy($x->{value}); next;
-      }
-    if (!($r = ref($x->{$k})))
-      {
-      $self->{$k} = $x->{$k}; next;
-      }
-    if ($r eq 'SCALAR')
-      {
-      $self->{$k} = \${$x->{$k}};
-      }
-    elsif ($r eq 'ARRAY')
-      {
-      $self->{$k} = [ @{$x->{$k}} ];
-      }
-    elsif ($r eq 'HASH')
-      {
-      # only one level deep!
-      foreach my $h (keys %{$x->{$k}})
-        {
-        $self->{$k}->{$h} = $x->{$k}->{$h};
-        }
-      }
-    else # normal ref
-      {
-      my $xk = $x->{$k};
-      if ($xk->can('copy'))
-        {
-       $self->{$k} = $xk->copy();
-        }
-      else
-       {
-       $self->{$k} = $xk->new($xk);
-       }
-      }
-    }
+  my $self = bless {}, $c;
+
+  $self->{sign} = $x->{sign};
+  $self->{value} = $CALC->_copy($x->{value});
+  $self->{_a} = $x->{_a} if defined $x->{_a};
+  $self->{_p} = $x->{_p} if defined $x->{_p};
   $self;
   }
 
@@ -523,17 +505,17 @@ sub new
   if ((!ref $wanted) && ($wanted =~ /^([+-]?)[1-9][0-9]*\z/))
     {
     $self->{sign} = $1 || '+';
-    my $ref = \$wanted;
+
     if ($wanted =~ /^[+-]/)
      {
       # remove sign without touching wanted to make it work with constants
-      my $t = $wanted; $t =~ s/^[+-]//; $ref = \$t;
+      my $t = $wanted; $t =~ s/^[+-]//;
+      $self->{value} = $CALC->_new($t);
+      }
+    else
+      {
+      $self->{value} = $CALC->_new($wanted);
       }
-    # force to string version (otherwise Pari is unhappy about overflowed
-    # constants, for instance)
-    # not good, BigInt shouldn't need to know about alternative libs:
-    # $ref = \"$$ref" if $CALC eq 'Math::BigInt::Pari';
-    $self->{value} = $CALC->_new($ref);
     no strict 'refs';
     if ( (defined $a) || (defined $p) 
         || (defined ${"${class}::precision"})
@@ -546,14 +528,13 @@ sub new
     }
 
   # handle '+inf', '-inf' first
-  if ($wanted =~ /^[+-]?inf$/)
+  if ($wanted =~ /^[+-]?inf\z/)
     {
-    $self->{value} = $CALC->_zero();
-    $self->{sign} = $wanted; $self->{sign} = '+inf' if $self->{sign} eq 'inf';
-    return $self;
+    $self->{sign} = $wanted;           # set a default sign for bstr()
+    return $self->binf($wanted);
     }
   # split str in m mantissa, e exponent, i integer, f fraction, v value, s sign
-  my ($mis,$miv,$mfv,$es,$ev) = _split(\$wanted);
+  my ($mis,$miv,$mfv,$es,$ev) = _split($wanted);
   if (!ref $mis)
     {
     if ($_trap_nan)
@@ -626,7 +607,7 @@ sub new
       }
     }
   $self->{sign} = '+' if $$miv eq '0';                 # normalize -0 => +0
-  $self->{value} = $CALC->_new($miv) if $self->{sign} =~ /^[+-]$/;
+  $self->{value} = $CALC->_new($$miv) if $self->{sign} =~ /^[+-]$/;
   # if any of the globals is set, use them to round and store them inside $self
   # do not round for new($x,undef,undef) since that is used by MBF to signal
   # no rounding
@@ -663,7 +644,7 @@ sub bnan
     }
   $self->{sign} = $nan;
   delete $self->{_a}; delete $self->{_p};      # rounding NaN is silly
-  return $self;
+  $self;
   }
 
 sub binf
@@ -681,7 +662,7 @@ sub binf
   if (${"${class}::_trap_inf"})
     {
     require Carp;
-    Carp::croak ("Tried to set $self to +-inf in $class\::binfn()");
+    Carp::croak ("Tried to set $self to +-inf in $class\::binf()");
     }
   $self->import() if $IMPORT == 0;             # make require work
   return if $self->modify('binf');
@@ -698,14 +679,14 @@ sub binf
   $sign = $sign . 'inf' if $sign !~ /inf$/;    # - => -inf
   $self->{sign} = $sign;
   ($self->{_a},$self->{_p}) = @_;              # take over requested rounding
-  return $self;
+  $self;
   }
 
 sub bzero
   {
   # create a bigint '+0', if given a BigInt, set it to 0
   my $self = shift;
-  $self = $class if !defined $self;
+  $self = __PACKAGE__ if !defined $self;
  
   if (!ref($self))
     {
@@ -746,7 +727,7 @@ sub bzero
 sub bone
   {
   # create a bigint '+1' (or -1 if given sign '-'),
-  # if given a BigInt, set it to +1 or -1, respecively
+  # if given a BigInt, set it to +1 or -1, respectively
   my $self = shift;
   my $sign = shift; $sign = '+' if !defined $sign || $sign ne '-';
   $self = $class if !defined $self;
@@ -796,8 +777,7 @@ sub bsstr
   # (ref to BFLOAT or num_str ) return num_str
   # Convert number from internal format to scientific string format.
   # internal format is always normalized (no leading zeros, "-0E0" => "+0E0")
-  my $x = shift; $class = ref($x) || $x; $x = $class->new(shift) if !ref($x); 
-  # my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); 
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); 
 
   if ($x->{sign} !~ /^[+-]$/)
     {
@@ -807,14 +787,13 @@ sub bsstr
   my ($m,$e) = $x->parts();
   #$m->bstr() . 'e+' . $e->bstr();     # e can only be positive in BigInt
   # 'e+' because E can only be positive in BigInt
-  $m->bstr() . 'e+' . ${$CALC->_str($e->{value})}
+  $m->bstr() . 'e+' . $CALC->_str($e->{value})
   }
 
 sub bstr 
   {
   # make a string from bigint object
-  my $x = shift; $class = ref($x) || $x; $x = $class->new(shift) if !ref($x); 
-  # my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); 
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); 
 
   if ($x->{sign} !~ /^[+-]$/)
     {
@@ -822,7 +801,7 @@ sub bstr
     return 'inf';                                      # +inf
     }
   my $es = ''; $es = $x->{sign} if $x->{sign} eq '-';
-  $es.${$CALC->_str($x->{value})};
+  $es.$CALC->_str($x->{value});
   }
 
 sub numify 
@@ -867,9 +846,6 @@ sub _find_round_parameters
   # $r round_mode, if given by caller
   # @args all 'other' arguments (0 for unary, 1 for binary ops)
 
-  # leave bigfloat parts alone
-  return ($self) if exists $self->{_f} && ($self->{_f} & MB_NEVER_ROUND) != 0;
-
   my $c = ref($self);                          # find out class of argument(s)
   no strict 'refs';
 
@@ -927,9 +903,6 @@ sub round
   # $r round_mode, if given by caller
   # @args all 'other' arguments (0 for unary, 1 for binary ops)
 
-  # leave bigfloat parts alone
-  return ($self) if exists $self->{_f} && ($self->{_f} & MB_NEVER_ROUND) != 0;
-
   my $c = ref($self);                          # find out class of argument(s)
   no strict 'refs';
 
@@ -980,7 +953,8 @@ sub round
     {
     $self->bfround($p,$r) if !defined $self->{_p} || $self->{_p} <= $p;
     }
-  $self->bnorm();                      # after round, normalize
+  # bround() or bfround() already callled bnorm() if necc.
+  $self;
   }
 
 sub bnorm
@@ -995,7 +969,7 @@ sub babs
   {
   # (BINT or num_str) return BINT
   # make number absolute, or return absolute BINT from string
-  my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
 
   return $x if $x->modify('babs');
   # post-normalized abs for internal use (does nothing for NaN)
@@ -1007,12 +981,12 @@ sub bneg
   { 
   # (BINT or num_str) return BINT
   # negate number or make a negated number from string
-  my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+  my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
   
   return $x if $x->modify('bneg');
 
-  # for +0 dont negate (to have always normalized)
-  $x->{sign} =~ tr/+-/-+/ if !$x->is_zero();   # does nothing for NaN
+  # for +0 dont negate (to have always normalized +0). Does nothing for 'NaN'
+  $x->{sign} =~ tr/+-/-+/ unless ($x->{sign} eq '+' && $CALC->_is_zero($x->{value}));
   $x;
   }
 
@@ -1083,7 +1057,8 @@ sub bacmp
     # 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;
     }
   $CALC->_acmp($x->{value},$y->{value});       # lib does only 0,1,-1
   }
@@ -1149,8 +1124,7 @@ sub badd
       $x->{value} = $CALC->_sub($x->{value}, $y->{value}); # abs sub
       }
     }
-  $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
-  $x;
+  $x->round(@r);
   }
 
 sub bsub 
@@ -1168,17 +1142,22 @@ sub bsub
 
   return $x if $x->modify('bsub');
 
-# upgrade done by badd():
-#  return $upgrade->badd($x,$y,@r) if defined $upgrade &&
-#   ((!$x->isa($self)) || (!$y->isa($self)));
+  return $upgrade->new($x)->bsub($upgrade->new($y),@r) if defined $upgrade &&
+   ((!$x->isa($self)) || (!$y->isa($self)));
 
-  if ($y->is_zero())
-    { 
-    $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
-    return $x;
-    }
+  return $x->round(@r) if $y->is_zero();
 
+  # To correctly handle the lone special case $x->bsub($x), we note the sign
+  # of $x, then flip the sign from $y, and if the sign of $x did change, too,
+  # then we caught the special case:
+  my $xsign = $x->{sign};
   $y->{sign} =~ tr/+\-/-+/;    # does nothing for NaN
+  if ($xsign ne $x->{sign})
+    {
+    # special case of $x->bsub($x) results in 0
+    return $x->bzero(@r) if $xsign =~ /^[+-]$/;
+    return $x->bnan();          # NaN, -inf, +inf
+    }
   $x->badd($y,@r);             # badd does not leave internal zeros
   $y->{sign} =~ tr/+\-/-+/;    # refix $y (does nothing for NaN)
   $x;                          # already rounded by badd() or no round necc.
@@ -1193,15 +1172,13 @@ sub binc
   if ($x->{sign} eq '+')
     {
     $x->{value} = $CALC->_inc($x->{value});
-    $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
-    return $x;
+    return $x->round($a,$p,$r);
     }
   elsif ($x->{sign} eq '-')
     {
     $x->{value} = $CALC->_dec($x->{value});
     $x->{sign} = '+' if $CALC->_is_zero($x->{value}); # -1 +1 => -0 => +0
-    $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
-    return $x;
+    return $x->round($a,$p,$r);
     }
   # inf, nan handling etc
   $x->badd($self->bone(),$a,$p,$r);            # badd does round
@@ -1215,12 +1192,12 @@ sub bdec
   
   if ($x->{sign} eq '-')
     {
-    # < 0
+    # x already < 0
     $x->{value} = $CALC->_inc($x->{value});
     } 
   else
     {
-    return $x->badd($self->bone('-'),@r) unless $x->{sign} eq '+'; # inf/NaN
+    return $x->badd($self->bone('-'),@r) unless $x->{sign} eq '+';     # inf or NaN
     # >= 0
     if ($CALC->_is_zero($x->{value}))
       {
@@ -1233,8 +1210,7 @@ sub bdec
       $x->{value} = $CALC->_dec($x->{value});
       }
     }
-  $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
-  $x;
+  $x->round(@r);
   }
 
 sub blog
@@ -1243,30 +1219,26 @@ sub blog
   # $base of $x)
 
   # set up parameters
-  my ($self,$x,$base,@r) = (ref($_[0]),@_);
+  my ($self,$x,$base,@r) = (undef,@_);
   # objectify is costly, so avoid it
   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
     {
-    ($self,$x,$base,@r) = objectify(2,$class,@_);
+    ($self,$x,$base,@r) = objectify(1,ref($x),@_);
     }
+  
+  return $x if $x->modify('blog');
 
   # inf, -inf, NaN, <0 => NaN
   return $x->bnan()
-   if $x->{sign} ne '+' || $base->{sign} ne '+';
-  
-  return $upgrade->blog($upgrade->new($x),$base,@r) if 
-    defined $upgrade && (ref($x) ne $upgrade || ref($base) ne $upgrade);
+   if $x->{sign} ne '+' || (defined $base && $base->{sign} ne '+');
 
-  if ($CAN{log_int})
-    {
-    my ($rc,$exact) = $CALC->_log_int($x->{value},$base->{value});
-    return $x->bnan() unless defined $rc;
-    $x->{value} = $rc;
-    return $x->round(@r);
-    }
+  return $upgrade->blog($upgrade->new($x),$base,@r) if 
+    defined $upgrade;
 
-  require $EMU_LIB;
-  __emu_blog($self,$x,$base,@r);
+  my ($rc,$exact) = $CALC->_log_int($x->{value},$base->{value});
+  return $x->bnan() unless defined $rc;                # not possible to take log?
+  $x->{value} = $rc;
+  $x->round(@r);
   }
 
 sub blcm 
@@ -1284,7 +1256,12 @@ sub blcm
     {
     $x = $class->new($y);
     }
-  while (@_) { $x = __lcm($x,shift); } 
+  my $self = ref($x);
+  while (@_) 
+    {
+    my $y = shift; $y = $self->new($y) if !ref ($y);
+    $x = __lcm($x,$y);
+    } 
   $x;
   }
 
@@ -1295,28 +1272,19 @@ sub bgcd
   # GCD -- Euclids algorithm, variant C (Knuth Vol 3, pg 341 ff)
 
   my $y = shift;
-  $y = __PACKAGE__->new($y) if !ref($y);
+  $y = $class->new($y) if !ref($y);
   my $self = ref($y);
-  my $x = $y->copy();          # keep arguments
-  if ($CAN{gcd})
-    {
-    while (@_)
-      {
-      $y = shift; $y = $self->new($y) if !ref($y);
-      next if $y->is_zero();
-      return $x->bnan() if $y->{sign} !~ /^[+-]$/;     # y NaN?
-      $x->{value} = $CALC->_gcd($x->{value},$y->{value}); last if $x->is_one();
-      }
-    }
-  else
+  my $x = $y->copy()->babs();                  # keep arguments
+  return $x->bnan() if $x->{sign} !~ /^[+-]$/; # x NaN?
+
+  while (@_)
     {
-    while (@_)
-      {
-      $y = shift; $y = $self->new($y) if !ref($y);
-      $x = __gcd($x,$y->copy()); last if $x->is_one(); # _gcd handles NaN
-      } 
+    $y = shift; $y = $self->new($y) if !ref($y);
+    return $x->bnan() if $y->{sign} !~ /^[+-]$/;       # y NaN?
+    $x->{value} = $CALC->_gcd($x->{value},$y->{value});
+    last if $CALC->_is_one($x->{value});
     }
-  $x->babs();
+  $x;
   }
 
 sub bnot 
@@ -1398,8 +1366,11 @@ sub is_positive
   {
   # return true when arg (BINT or num_str) is positive (>= 0)
   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
-  
-  $x->{sign} =~ /^\+/ ? 1 : 0;         # +inf is also positive, but NaN not
+
+  return 1 if $x->{sign} eq '+inf';                    # +inf is positive
+  # 0+ is neither positive nor negative
+  ($x->{sign} eq '+' && !$x->is_zero()) ? 1 : 0;       
   }
 
 sub is_negative
@@ -1407,7 +1378,7 @@ sub is_negative
   # return true when arg (BINT or num_str) is negative (< 0)
   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
   
-  $x->{sign} =~ /^-/ ? 1 : 0;          # -inf is also negative, but NaN not
+  $x->{sign} =~ /^-/ ? 1 : 0;          # -inf is negative, but NaN is not
   }
 
 sub is_int
@@ -1449,9 +1420,9 @@ sub bmul
     return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/); 
     return $x->binf('-');
     }
-  
-  return $upgrade->bmul($x,$y,@r)
-   if defined $upgrade && $y->isa($upgrade);
+
+  return $upgrade->bmul($x,$upgrade->new($y),@r)
+   if defined $upgrade && !$y->isa($self);
   
   $r[3] = $y;                          # no push here
 
@@ -1460,8 +1431,7 @@ sub bmul
   $x->{value} = $CALC->_mul($x->{value},$y->{value});  # do actual math
   $x->{sign} = '+' if $CALC->_is_zero($x->{value});    # no -0
 
-  $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
-  $x;
+  $x->round(@r);
   }
 
 sub _div_inf
@@ -1543,7 +1513,7 @@ sub bdiv
     $x->{sign} = '+' if $CALC->_is_zero($x->{value});
     $rem->{_a} = $x->{_a};
     $rem->{_p} = $x->{_p};
-    $x->round(@r) if !exists $x->{_f} || ($x->{_f} & MB_NEVER_ROUND) == 0;
+    $x->round(@r);
     if (! $CALC->_is_zero($rem->{value}))
       {
       $rem->{sign} = $y->{sign};
@@ -1553,15 +1523,14 @@ sub bdiv
       {
       $rem->{sign} = '+';                      # dont leave -0
       }
-    $rem->round(@r) if !exists $rem->{_f} || ($rem->{_f} & MB_NEVER_ROUND) == 0;
+    $rem->round(@r);
     return ($x,$rem);
     }
 
   $x->{value} = $CALC->_div($x->{value},$y->{value});
   $x->{sign} = '+' if $CALC->_is_zero($x->{value});
 
-  $x->round(@r) if !exists $x->{_f} || ($x->{_f} & MB_NEVER_ROUND) == 0;
-  $x;
+  $x->round(@r);
   }
 
 ###############################################################################
@@ -1590,36 +1559,19 @@ sub bmod
     return $x->round(@r);
     }
 
-  if ($CAN{mod})
+  # calc new sign and in case $y == +/- 1, return $x
+  $x->{value} = $CALC->_mod($x->{value},$y->{value});
+  if (!$CALC->_is_zero($x->{value}))
     {
-    # calc new sign and in case $y == +/- 1, return $x
-    $x->{value} = $CALC->_mod($x->{value},$y->{value});
-    if (!$CALC->_is_zero($x->{value}))
-      {
-      my $xsign = $x->{sign};
-      $x->{sign} = $y->{sign};
-      if ($xsign ne $y->{sign})
-        {
-        my $t = $CALC->_copy($x->{value});             # copy $x
-        $x->{value} = $CALC->_sub($y->{value},$t,1);   # $y-$x
-        }
-      }
-    else
-      {
-      $x->{sign} = '+';                                # dont leave -0
-      }
-    $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
-    return $x;
+    $x->{value} = $CALC->_sub($y->{value},$x->{value},1)       # $y-$x
+      if ($x->{sign} ne $y->{sign});
+    $x->{sign} = $y->{sign};
     }
-  # disable upgrade temporarily, otherwise endless loop due to bdiv()
-  local $upgrade = undef;
-  my ($t,$rem) = $self->bdiv($x->copy(),$y,@r);        # slow way (also rounds)
-  # modify in place
-  foreach (qw/value sign _a _p/)
+   else
     {
-    $x->{$_} = $rem->{$_};
+    $x->{sign} = '+';                          # dont leave -0
     }
-  $x;
+  $x->round(@r);
   }
 
 sub bmodinv
@@ -1630,7 +1582,7 @@ sub bmodinv
   # (i.e. their gcd is not one) then NaN is returned.
 
   # set up parameters
-  my ($self,$x,$y,@r) = (ref($_[0]),@_);
+  my ($self,$x,$y,@r) = (undef,@_);
   # objectify is costly, so avoid it
   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
     {
@@ -1648,19 +1600,13 @@ sub bmodinv
   # put least residue into $x if $x was negative, and thus make it positive
   $x->bmod($y) if $x->{sign} eq '-';
 
-  if ($CAN{modinv})
-    {
-    my $sign;
-    ($x->{value},$sign) = $CALC->_modinv($x->{value},$y->{value});
-    return $x->bnan() if !defined $x->{value};         # in case no GCD found
-    return $x if !defined $sign;                       # already real result
-    $x->{sign} = $sign;                                        # flip/flop see below
-    $x->bmod($y);                                      # calc real result
-    return $x;
-    }
-
-  require $EMU_LIB;
-  __emu_bmodinv($self,$x,$y,@r);
+  my $sign;
+  ($x->{value},$sign) = $CALC->_modinv($x->{value},$y->{value});
+  return $x->bnan() if !defined $x->{value};           # in case no GCD found
+  return $x if !defined $sign;                 # already real result
+  $x->{sign} = $sign;                          # flip/flop see below
+  $x->bmod($y);                                        # calc real result
+  $x;
   }
 
 sub bmodpow
@@ -1688,15 +1634,9 @@ sub bmodpow
   # check num for valid values (also NaN if there was no inverse but $exp < 0)
   return $num->bnan() if $num->{sign} !~ /^[+-]$/;
 
-  if ($CAN{modpow})
-    {
-    # $mod is positive, sign on $exp is ignored, result also positive
-    $num->{value} = $CALC->_modpow($num->{value},$exp->{value},$mod->{value});
-    return $num;
-    }
-
-  require $EMU_LIB;
-  __emu_bmodpow($self,$num,$exp,$mod,@r);
+  # $mod is positive, sign on $exp is ignored, result also positive
+  $num->{value} = $CALC->_modpow($num->{value},$exp->{value},$mod->{value});
+  $num;
   }
 
 ###############################################################################
@@ -1705,21 +1645,13 @@ sub bfac
   {
   # (BINT or num_str, BINT or num_str) return BINT
   # compute factorial number from $x, modify $x in place
-  my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
-
-  return $x if $x->modify('bfac');
-  return $x if $x->{sign} eq '+inf';           # inf => inf
-  return $x->bnan() if $x->{sign} ne '+';      # NaN, <0 etc => NaN
+  my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_);
 
-  if ($CAN{fac})
-    {
-    $x->{value} = $CALC->_fac($x->{value});
-    return $x->round(@r);
-    }
+  return $x if $x->modify('bfac') || $x->{sign} eq '+inf';     # inf => inf
+  return $x->bnan() if $x->{sign} ne '+';                      # NaN, <0 etc => NaN
 
-  require $EMU_LIB;
-  __emu_bfac($self,$x,@r);
+  $x->{value} = $CALC->_fac($x->{value});
+  $x->round(@r);
   }
  
 sub bpow 
@@ -1738,35 +1670,78 @@ sub bpow
 
   return $x if $x->modify('bpow');
 
+  return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
+
+  # inf handling
+  if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/))
+    {
+    if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/))
+      {
+      # +-inf ** +-inf
+      return $x->bnan();
+      }
+    # +-inf ** Y
+    if ($x->{sign} =~ /^[+-]inf/)
+      {
+      # +inf ** 0 => NaN
+      return $x->bnan() if $y->is_zero();
+      # -inf ** -1 => 1/inf => 0
+      return $x->bzero() if $y->is_one('-') && $x->is_negative();
+
+      # +inf ** Y => inf
+      return $x if $x->{sign} eq '+inf';
+
+      # -inf ** Y => -inf if Y is odd
+      return $x if $y->is_odd();
+      return $x->babs();
+      }
+    # X ** +-inf
+
+    # 1 ** +inf => 1
+    return $x if $x->is_one();
+    
+    # 0 ** inf => 0
+    return $x if $x->is_zero() && $y->{sign} =~ /^[+]/;
+
+    # 0 ** -inf => inf
+    return $x->binf() if $x->is_zero();
+
+    # -1 ** -inf => NaN
+    return $x->bnan() if $x->is_one('-') && $y->{sign} =~ /^[-]/;
+
+    # -X ** -inf => 0
+    return $x->bzero() if $x->{sign} eq '-' && $y->{sign} =~ /^[-]/;
+
+    # -1 ** inf => NaN
+    return $x->bnan() if $x->{sign} eq '-';
+
+    # X ** inf => inf
+    return $x->binf() if $y->{sign} =~ /^[+]/;
+    # X ** -inf => 0
+    return $x->bzero();
+    }
+
   return $upgrade->bpow($upgrade->new($x),$y,@r)
    if defined $upgrade && !$y->isa($self);
 
   $r[3] = $y;                                  # no push!
-  return $x if $x->{sign} =~ /^[+-]inf$/;      # -inf/+inf ** x
-  return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
 
   # cases 0 ** Y, X ** 0, X ** 1, 1 ** Y are handled by Calc or Emu
 
-  if ($x->{sign} eq '-' && $CALC->_is_one($x->{value}))
-    {
-    # if $x == -1 and odd/even y => +1/-1
-    return $y->is_odd() ? $x->round(@r) : $x->babs()->round(@r);
-    # my Casio FX-5500L has a bug here: -1 ** 2 is -1, but -1 * -1 is 1;
-    }
+  my $new_sign = '+';
+  $new_sign = $y->is_odd() ? '-' : '+' if ($x->{sign} ne '+'); 
+
+  # 0 ** -7 => ( 1 / (0 ** 7)) => 1 / 0 => +inf 
+  return $x->binf() 
+    if $y->{sign} eq '-' && $x->{sign} eq '+' && $CALC->_is_zero($x->{value});
   # 1 ** -y => 1 / (1 ** |y|)
   # so do test for negative $y after above's clause
-  return $x->bnan() if $y->{sign} eq '-' && !$x->is_one();
+  return $x->bnan() if $y->{sign} eq '-' && !$CALC->_is_one($x->{value});
 
-  if ($CAN{pow})
-    {
-    $x->{value} = $CALC->_pow($x->{value},$y->{value});
-    $x->{sign} = '+' if $CALC->_is_zero($y->{value});
-    $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
-    return $x;
-    }
-
-  require $EMU_LIB;
-  __emu_bpow($self,$x,$y,@r);
+  $x->{value} = $CALC->_pow($x->{value},$y->{value});
+  $x->{sign} = $new_sign;
+  $x->{sign} = '+' if $CALC->_is_zero($y->{value});
+  $x->round(@r);
   }
 
 sub blsft 
@@ -1788,13 +1763,8 @@ sub blsft
 
   $n = 2 if !defined $n; return $x->bnan() if $n <= 0 || $y->{sign} eq '-';
 
-  my $t; $t = $CALC->_lsft($x->{value},$y->{value},$n) if $CAN{lsft};
-  if (defined $t)
-    {
-    $x->{value} = $t; return $x->round(@r);
-    }
-  # fallback
-  $x->bmul( $self->bpow($n, $y, @r), @r );
+  $x->{value} = $CALC->_lsft($x->{value},$y->{value},$n);
+  $x->round(@r);
   }
 
 sub brsft 
@@ -1854,15 +1824,8 @@ sub brsft
     $x->bdec();                                # n == 2, but $y == 1: this fixes it
     }
 
-  my $t; $t = $CALC->_rsft($x->{value},$y->{value},$n) if $CAN{rsft};
-  if (defined $t)
-    {
-    $x->{value} = $t;
-    return $x->round(@r);
-    }
-  # fallback
-  $x->bdiv($self->bpow($n,$y, @r), @r);
-  $x;
+  $x->{value} = $CALC->_rsft($x->{value},$y->{value},$n);
+  $x->round(@r);
   }
 
 sub band 
@@ -1887,7 +1850,7 @@ sub band
   my $sx = $x->{sign} eq '+' ? 1 : -1;
   my $sy = $y->{sign} eq '+' ? 1 : -1;
   
-  if ($CAN{and} && $sx == 1 && $sy == 1)
+  if ($sx == 1 && $sy == 1)
     {
     $x->{value} = $CALC->_and($x->{value},$y->{value});
     return $x->round(@r);
@@ -1919,8 +1882,6 @@ sub bior
   return $x if $x->modify('bior');
   $r[3] = $y;                          # no push!
 
-  local $Math::BigInt::upgrade = undef;
-
   return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
 
   my $sx = $x->{sign} eq '+' ? 1 : -1;
@@ -1929,7 +1890,7 @@ sub bior
   # the sign of X follows the sign of X, e.g. sign of Y irrelevant for bior()
   
   # don't use lib for negative values
-  if ($CAN{or} && $sx == 1 && $sy == 1)
+  if ($sx == 1 && $sy == 1)
     {
     $x->{value} = $CALC->_or($x->{value},$y->{value});
     return $x->round(@r);
@@ -1968,7 +1929,7 @@ sub bxor
   my $sy = $y->{sign} eq '+' ? 1 : -1;
 
   # don't use lib for negative values
-  if ($CAN{xor} && $sx == 1 && $sy == 1)
+  if ($sx == 1 && $sy == 1)
     {
     $x->{value} = $CALC->_xor($x->{value},$y->{value});
     return $x->round(@r);
@@ -1996,8 +1957,9 @@ sub length
 sub digit
   {
   # return the nth decimal digit, negative values count backward, 0 is right
-  my ($self,$x,$n) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
+  my ($self,$x,$n) = ref($_[0]) ? (undef,@_) : objectify(1,@_);
 
+  $n = $n->numify() if ref($n);
   $CALC->_digit($x->{value},$n||0);
   }
 
@@ -2007,20 +1969,15 @@ sub _trailing_zeros
   my $x = shift;
   $x = $class->new($x) unless ref $x;
 
-  return 0 if $x->is_zero() || $x->is_odd() || $x->{sign} !~ /^[+-]$/;
+  return 0 if $x->{sign} !~ /^[+-]$/;  # NaN, inf, -inf etc
 
-  return $CALC->_zeros($x->{value}) if $CAN{zeros};
-
-  # if not: since we do not know underlying internal representation:
-  my $es = "$x"; $es =~ /([0]*)$/;
-  return 0 if !defined $1;     # no zeros
-  CORE::length("$1");          # as string, not as +0!
+  $CALC->_zeros($x->{value});          # must handle odd values, 0 etc
   }
 
 sub bsqrt
   {
   # calculate square root of $x
-  my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
+  my ($self,$x,@r) = ref($_[0]) ? (undef,@_) : objectify(1,@_);
 
   return $x if $x->modify('bsqrt');
 
@@ -2029,14 +1986,8 @@ sub bsqrt
 
   return $upgrade->bsqrt($x,@r) if defined $upgrade;
 
-  if ($CAN{sqrt})
-    {
-    $x->{value} = $CALC->_sqrt($x->{value});
-    return $x->round(@r);
-    }
-
-  require $EMU_LIB;
-  __emu_bsqrt($self,$x,@r);
+  $x->{value} = $CALC->_sqrt($x->{value});
+  $x->round(@r);
   }
 
 sub broot
@@ -2065,14 +2016,8 @@ sub broot
 
   return $upgrade->new($x)->broot($upgrade->new($y),@r) if defined $upgrade;
 
-  if ($CAN{root})
-    {
-    $x->{value} = $CALC->_root($x->{value},$y->{value});
-    return $x->round(@r);
-    }
-
-  require $EMU_LIB;
-  __emu_broot($self,$x,$y,@r);
+  $x->{value} = $CALC->_root($x->{value},$y->{value});
+  $x->round(@r);
   }
 
 sub exponent
@@ -2122,40 +2067,38 @@ sub bfround
   {
   # precision: round to the $Nth digit left (+$n) or right (-$n) from the '.'
   # $n == 0 || $n == 1 => round to integer
-  my $x = shift; $x = $class->new($x) unless ref $x;
+  my $x = shift; my $self = ref($x) || $x; $x = $self->new($x) unless ref $x;
 
-  my ($scale,$mode) = $x->_scale_p($x->precision(),$x->round_mode(),@_);
+  my ($scale,$mode) = $x->_scale_p(@_);
 
   return $x if !defined $scale || $x->modify('bfround');       # no-op
 
   # no-op for BigInts if $n <= 0
   $x->bround( $x->length()-$scale, $mode) if $scale > 0;
 
-  $x->{_a} = undef;                            # bround sets {_a}
-  $x->{_p} = $scale;                           # so correct it
+  delete $x->{_a};     # delete to save memory
+  $x->{_p} = $scale;   # store new _p
   $x;
   }
 
 sub _scan_for_nonzero
   {
-  # internal, used by bround()
-  my ($x,$pad,$xs) = @_;
+  # internal, used by bround() to scan for non-zeros after a '5'
+  my ($x,$pad,$xs,$len) = @_;
  
-  my $len = $x->length();
-  return 0 if $len == 1;               # '5' is trailed by invisible zeros
+  return 0 if $len == 1;               # "5" is trailed by invisible zeros
   my $follow = $pad - 1;
   return 0 if $follow > $len || $follow < 1;
 
-  # since we do not know underlying represention of $x, use decimal string
-  my $r = substr ("$x",-$follow);
-  $r =~ /[^0]/ ? 1 : 0;
+  # use the string form to check whether only '0's follow or not
+  substr ($xs,-$follow) =~ /[^0]/ ? 1 : 0;
   }
 
 sub fround
   {
   # Exists to make life easier for switch between MBF and MBI (should we
   # autoload fxxx() like MBF does for bxxx()?)
-  my $x = shift;
+  my $x = shift; $x = $class->new($x) unless ref $x;
   $x->bround(@_);
   }
 
@@ -2168,9 +2111,8 @@ sub bround
   # do not return $x->bnorm(), but $x
 
   my $x = shift; $x = $class->new($x) unless ref $x;
-  my ($scale,$mode) = $x->_scale_a($x->accuracy(),$x->round_mode(),@_);
-  return $x if !defined $scale;                        # no-op
-  return $x if $x->modify('bround');
+  my ($scale,$mode) = $x->_scale_a(@_);
+  return $x if !defined $scale || $x->modify('bround');        # no-op
   
   if ($x->is_zero() || $scale == 0)
     {
@@ -2198,16 +2140,16 @@ sub bround
   $pad = $len - $scale;
   $pad = abs($scale-1) if $scale < 0;
 
-  # do not use digit(), it is costly for binary => decimal
-
+  # do not use digit(), it is very costly for binary => decimal
+  # getting the entire string is also costly, but we need to do it only once
   my $xs = $CALC->_str($x->{value});
   my $pl = -$pad-1;
 
   # pad:   123: 0 => -1, at 1 => -2, at 2 => -3, at 3 => -4
   # pad+1: 123: 0 => 0,  at 1 => -1, at 2 => -2, at 3 => -3
-  $digit_round = '0'; $digit_round = substr($$xs,$pl,1) if $pad <= $len;
+  $digit_round = '0'; $digit_round = substr($xs,$pl,1) if $pad <= $len;
   $pl++; $pl ++ if $pad >= $len;
-  $digit_after = '0'; $digit_after = substr($$xs,$pl,1) if $pad > 0;
+  $digit_after = '0'; $digit_after = substr($xs,$pl,1) if $pad > 0;
 
   # in case of 01234 we round down, for 6789 up, and only in case 5 we look
   # closer at the remaining digits of the original $x, remember decision
@@ -2217,7 +2159,7 @@ sub bround
     ($digit_after =~ /[01234]/)                        ||      # round down anyway,
                                                        # 6789 => round up
     ($digit_after eq '5')                      &&      # not 5000...0000
-    ($x->_scan_for_nonzero($pad,$xs) == 0)             &&
+    ($x->_scan_for_nonzero($pad,$xs,$len) == 0)                &&
     (
      ($mode eq 'even') && ($digit_round =~ /[24680]/) ||
      ($mode eq 'odd')  && ($digit_round =~ /[13579]/) ||
@@ -2229,8 +2171,8 @@ sub bround
        
   if (($pad > 0) && ($pad <= $len))
     {
-    substr($$xs,-$pad,$pad) = '0' x $pad;
-    $put_back = 1;
+    substr($xs,-$pad,$pad) = '0' x $pad;               # replace with '00...'
+    $put_back = 1;                                     # need to put back
     }
   elsif ($pad > $len)
     {
@@ -2239,22 +2181,22 @@ sub bround
 
   if ($round_up)                                       # what gave test above?
     {
-    $put_back = 1;
-    $pad = $len, $$xs = '0' x $pad if $scale < 0;      # tlr: whack 0.51=>1.0  
+    $put_back = 1;                                     # need to put back
+    $pad = $len, $xs = '0' x $pad if $scale < 0;       # tlr: whack 0.51=>1.0  
 
     # we modify directly the string variant instead of creating a number and
     # adding it, since that is faster (we already have the string)
     my $c = 0; $pad ++;                                # for $pad == $len case
     while ($pad <= $len)
       {
-      $c = substr($$xs,-$pad,1) + 1; $c = '0' if $c eq '10';
-      substr($$xs,-$pad,1) = $c; $pad++;
+      $c = substr($xs,-$pad,1) + 1; $c = '0' if $c eq '10';
+      substr($xs,-$pad,1) = $c; $pad++;
       last if $c != 0;                         # no overflow => early out
       }
-    $$xs = '1'.$$xs if $c == 0;
+    $xs = '1'.$xs if $c == 0;
 
     }
-  $x->{value} = $CALC->_new($xs) if $put_back == 1;    # put back in if needed
+  $x->{value} = $CALC->_new($xs) if $put_back == 1;    # put back, if needed
 
   $x->{_a} = $scale if $scale >= 0;
   if ($scale < 0)
@@ -2298,13 +2240,7 @@ sub as_hex
 
   my $s = '';
   $s = $x->{sign} if $x->{sign} eq '-';
-  if ($CAN{as_hex})
-    {
-    return $s . ${$CALC->_as_hex($x->{value})};
-    }
-
-  require $EMU_LIB;
-  __emu_as_hex(ref($x),$x,$s);
+  $s . $CALC->_as_hex($x->{value});
   }
 
 sub as_bin
@@ -2315,14 +2251,7 @@ sub as_bin
   return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
 
   my $s = ''; $s = $x->{sign} if $x->{sign} eq '-';
-  if ($CAN{as_bin})
-    {
-    return $s . ${$CALC->_as_bin($x->{value})};
-    }
-
-  require $EMU_LIB;
-  __emu_as_bin(ref($x),$x,$s);
-
+  return $s . $CALC->_as_bin($x->{value});
   }
 
 ##############################################################################
@@ -2335,7 +2264,7 @@ sub objectify
   # the first argument is number of args objectify() should look at it will
   # return $count+1 elements, the first will be a classname. This is because
   # overloaded '""' calls bstr($object,undef,undef) and this would result in
-  # useless objects beeing created and thrown away. So we cannot simple loop
+  # useless objects being created and thrown away. So we cannot simple loop
   # over @_. If the given count is 0, all arguments will be used.
  
   # If the second arg is a ref, use it as class.
@@ -2425,6 +2354,18 @@ sub objectify
   @a;
   }
 
+sub _register_callback
+  {
+  my ($class,$callback) = @_;
+
+  if (ref($callback) ne 'CODE')
+    { 
+    require Carp;
+    Carp::croak ("$callback is not a coderef");
+    }
+  $CALLBACKS{$class} = $callback;
+  }
+
 sub import 
   {
   my $self = shift;
@@ -2458,13 +2399,21 @@ sub import
       }
     }
   # any non :constant stuff is handled by our parent, Exporter
-  # even if @_ is empty, to give it a chance 
-  $self->SUPER::import(@a);                    # need it for subclasses
-  $self->export_to_level(1,$self,@a);          # need it for MBF
+  if (@a > 0)
+    {
+    require Exporter;
+    $self->SUPER::import(@a);                  # need it for subclasses
+    $self->export_to_level(1,$self,@a);                # need it for MBF
+    }
 
   # try to load core math lib
   my @c = split /\s*,\s*/,$CALC;
-  push @c,'Calc';                              # if all fail, try this
+  foreach (@c)
+    {
+    $_ =~ tr/a-zA-Z0-9://cd;                   # limit to sane characters
+    }
+  push @c, 'FastCalc', 'Calc';                 # if all fail, try these
   $CALC = '';                                  # signal error
   foreach my $lib (@c)
     {
@@ -2473,8 +2422,8 @@ sub import
     $lib =~ s/\.pm$//;
     if ($] < 5.006)
       {
-      # Perl < 5.6.0 dies with "out of memory!" when eval() and ':constant' is
-      # used in the same script, or eval inside import().
+      # Perl < 5.6.0 dies with "out of memory!" when eval("") and ':constant' is
+      # used in the same script, or eval("") inside import().
       my @parts = split /::/, $lib;             # Math::BigInt => Math BigInt
       my $file = pop @parts; $file .= '.pm';    # BigInt => BigInt.pm
       require File::Spec;
@@ -2485,151 +2434,156 @@ sub import
       {
       eval "use $lib qw/@c/;";
       }
-    $CALC = $lib, last if $@ eq '';    # no error in loading lib?
+    if ($@ eq '')
+      {
+      my $ok = 1;
+      # loaded it ok, see if the api_version() is high enough
+      if ($lib->can('api_version') && $lib->api_version() >= 1.0)
+       {
+       $ok = 0;
+       # api_version matches, check if it really provides anything we need
+        for my $method (qw/
+               one two ten
+               str num
+               add mul div sub dec inc
+               acmp len digit is_one is_zero is_even is_odd
+               is_two is_ten
+               new copy check from_hex from_bin as_hex as_bin zeros
+               rsft lsft xor and or
+               mod sqrt root fac pow modinv modpow log_int gcd
+        /)
+          {
+         if (!$lib->can("_$method"))
+           {
+           if (($WARN{$lib}||0) < 2)
+             {
+             require Carp;
+             Carp::carp ("$lib is missing method '_$method'");
+             $WARN{$lib} = 1;          # still warn about the lib
+             }
+            $ok++; last; 
+           }
+          }
+       }
+      if ($ok == 0)
+       {
+       $CALC = $lib;
+        last;                  # found a usable one, break
+       }
+      else
+       {
+       if (($WARN{$lib}||0) < 2)
+         {
+         my $ver = eval "\$$lib\::VERSION" || 'unknown';
+         require Carp;
+         Carp::carp ("Cannot load outdated $lib v$ver, please upgrade");
+         $WARN{$lib} = 2;              # never warn again
+         }
+        }
+      }
     }
   if ($CALC eq '')
     {
     require Carp;
     Carp::croak ("Couldn't load any math lib, not even 'Calc.pm'");
     }
-  _fill_can_cache();
-  }
 
-sub _fill_can_cache
-  {
-  # fill $CAN with the results of $CALC->can(...)
+  # notify callbacks
+  foreach my $class (keys %CALLBACKS)
+    {
+    &{$CALLBACKS{$class}}($CALC);
+    }
+
+  # Fill $CAN with the results of $CALC->can(...) for emulating lower math lib
+  # functions
 
   %CAN = ();
-  for my $method (qw/gcd mod modinv modpow fac pow lsft rsft 
-       and signed_and or signed_or xor signed_xor
-       from_hex as_hex from_bin as_bin
-       zeros sqrt root log_int log
-       /)
+  for my $method (qw/ signed_and signed_or signed_xor /)
     {
     $CAN{$method} = $CALC->can("_$method") ? 1 : 0;
     }
+
+  # import done
   }
 
 sub __from_hex
   {
+  # internal
   # convert a (ref to) big hex string to BigInt, return undef for error
   my $hs = shift;
 
   my $x = Math::BigInt->bzero();
   
   # strip underscores
-  $$hs =~ s/([0-9a-fA-F])_([0-9a-fA-F])/$1$2/g;        
-  $$hs =~ s/([0-9a-fA-F])_([0-9a-fA-F])/$1$2/g;        
+  $hs =~ s/([0-9a-fA-F])_([0-9a-fA-F])/$1$2/g; 
+  $hs =~ s/([0-9a-fA-F])_([0-9a-fA-F])/$1$2/g; 
   
-  return $x->bnan() if $$hs !~ /^[\-\+]?0x[0-9A-Fa-f]+$/;
+  return $x->bnan() if $hs !~ /^[\-\+]?0x[0-9A-Fa-f]+$/;
 
-  my $sign = '+'; $sign = '-' if ($$hs =~ /^-/);
+  my $sign = '+'; $sign = '-' if $hs =~ /^-/;
 
-  $$hs =~ s/^[+-]//;                   # strip sign
-  if ($CAN{'from_hex'})
-    {
-    $x->{value} = $CALC->_from_hex($hs);
-    }
-  else
-    {
-    # fallback to pure perl
-    my $mul = Math::BigInt->bone();
-    my $x65536 = Math::BigInt->new(65536);
-    my $len = CORE::length($$hs)-2;            # minus 2 for 0x
-    $len = int($len/4);                                # 4-digit parts, w/o '0x'
-    my $val; my $i = -4;
-    while ($len >= 0)
-      {
-      $val = substr($$hs,$i,4);
-      $val =~ s/^[+-]?0x// if $len == 0;       # for last part only because
-      $val = hex($val);                        # hex does not like wrong chars
-      $i -= 4; $len --;
-      $x += $mul * $val if $val != 0;
-      $mul *= $x65536 if $len >= 0;            # skip last mul
-      }
-    }
+  $hs =~ s/^[+-]//;                                            # strip sign
+  $x->{value} = $CALC->_from_hex($hs);
   $x->{sign} = $sign unless $CALC->_is_zero($x->{value});      # no '-0'
   $x;
   }
 
 sub __from_bin
   {
+  # internal
   # convert a (ref to) big binary string to BigInt, return undef for error
   my $bs = shift;
 
   my $x = Math::BigInt->bzero();
   # strip underscores
-  $$bs =~ s/([01])_([01])/$1$2/g;      
-  $$bs =~ s/([01])_([01])/$1$2/g;      
-  return $x->bnan() if $$bs !~ /^[+-]?0b[01]+$/;
+  $bs =~ s/([01])_([01])/$1$2/g;       
+  $bs =~ s/([01])_([01])/$1$2/g;       
+  return $x->bnan() if $bs !~ /^[+-]?0b[01]+$/;
 
-  my $sign = '+'; $sign = '-' if ($$bs =~ /^\-/);
-  $$bs =~ s/^[+-]//;                           # strip sign
-  if ($CAN{'from_bin'})
-    {
-    $x->{value} = $CALC->_from_bin($bs);
-    }
-  else
-    {
-    my $mul = Math::BigInt->bone();
-    my $x256 = Math::BigInt->new(256);
-    my $len = CORE::length($$bs)-2;            # minus 2 for 0b
-    $len = int($len/8);                                # 8-digit parts, w/o '0b'
-    my $val; my $i = -8;
-    while ($len >= 0)
-      {
-      $val = substr($$bs,$i,8);
-      $val =~ s/^[+-]?0b// if $len == 0;       # for last part only
-      #$val = oct('0b'.$val);  # does not work on Perl prior to 5.6.0
-      # slower:
-      # $val = ('0' x (8-CORE::length($val))).$val if CORE::length($val) < 8;
-      $val = ord(pack('B8',substr('00000000'.$val,-8,8)));
-      $i -= 8; $len --;
-      $x += $mul * $val if $val != 0;
-      $mul *= $x256 if $len >= 0;              # skip last mul
-      }
-    }
+  my $sign = '+'; $sign = '-' if $bs =~ /^\-/;
+  $bs =~ s/^[+-]//;                                            # strip sign
+
+  $x->{value} = $CALC->_from_bin($bs);
   $x->{sign} = $sign unless $CALC->_is_zero($x->{value});      # no '-0'
   $x;
   }
 
 sub _split
   {
-  # (ref to num_str) return num_str
-  # internal, take apart a string and return the pieces
-  # strip leading/trailing whitespace, leading zeros, underscore and reject
-  # invalid input
+  # input: num_str; output: undef for invalid or
+  # (\$mantissa_sign,\$mantissa_value,\$mantissa_fraction,\$exp_sign,\$exp_value)
+  # Internal, take apart a string and return the pieces.
+  # Strip leading/trailing whitespace, leading zeros, underscore and reject
+  # invalid input.
   my $x = shift;
 
   # strip white space at front, also extranous leading zeros
-  $$x =~ s/^\s*([-]?)0*([0-9])/$1$2/g; # will not strip '  .2'
-  $$x =~ s/^\s+//;                     # but this will                 
-  $$x =~ s/\s+$//g;                    # strip white space at end
+  $x =~ s/^\s*([-]?)0*([0-9])/$1$2/g;  # will not strip '  .2'
+  $x =~ s/^\s+//;                      # but this will                 
+  $x =~ s/\s+$//g;                     # strip white space at end
 
   # shortcut, if nothing to split, return early
-  if ($$x =~ /^[+-]?\d+\z/)
+  if ($x =~ /^[+-]?\d+\z/)
     {
-    $$x =~ s/^([+-])0*([0-9])/$2/; my $sign = $1 || '+';
-    return (\$sign, $x, \'', \'', \0);
+    $x =~ s/^([+-])0*([0-9])/$2/; my $sign = $1 || '+';
+    return (\$sign, \$x, \'', \'', \0);
     }
 
   # invalid starting char?
-  return if $$x !~ /^[+-]?(\.?[0-9]|0b[0-1]|0x[0-9a-fA-F])/;
+  return if $x !~ /^[+-]?(\.?[0-9]|0b[0-1]|0x[0-9a-fA-F])/;
 
-  return __from_hex($x) if $$x =~ /^[\-\+]?0x/;        # hex string
-  return __from_bin($x) if $$x =~ /^[\-\+]?0b/;        # binary string
+  return __from_hex($x) if $x =~ /^[\-\+]?0x/; # hex string
+  return __from_bin($x) if $x =~ /^[\-\+]?0b/; # binary string
   
   # strip underscores between digits
-  $$x =~ s/(\d)_(\d)/$1$2/g;
-  $$x =~ s/(\d)_(\d)/$1$2/g;           # do twice for 1_2_3
+  $x =~ s/(\d)_(\d)/$1$2/g;
+  $x =~ s/(\d)_(\d)/$1$2/g;            # do twice for 1_2_3
 
   # some possible inputs: 
   # 2.1234 # 0.12        # 1         # 1E1 # 2.134E1 # 434E-10 # 1.02009E-2 
   # .2            # 1_2_3.4_5_6 # 1.4E1_2_3  # 1e3 # +.2     # 0e999   
 
-  #return if $$x =~ /[Ee].*[Ee]/;      # more than one E => error
-
-  my ($m,$e,$last) = split /[Ee]/,$$x;
+  my ($m,$e,$last) = split /[Ee]/,$x;
   return if defined $last;             # last defined => 1e2E3 or others
   $e = '0' if !defined $e || $e eq "";
 
@@ -2668,29 +2622,15 @@ sub __lcm
   # does modify first argument
   # LCM
  
-  my $x = shift; my $ty = shift;
-  return $x->bnan() if ($x->{sign} eq $nan) || ($ty->{sign} eq $nan);
-  return $x * $ty / bgcd($x,$ty);
-  }
-
-sub __gcd
-  { 
-  # (BINT or num_str, BINT or num_str) return BINT
-  # does modify both arguments
-  # GCD -- Euclids algorithm E, Knuth Vol 2 pg 296
   my ($x,$ty) = @_;
-
-  return $x->bnan() if $x->{sign} !~ /^[+-]$/ || $ty->{sign} !~ /^[+-]$/;
-
-  while (!$ty->is_zero())
-    {
-    ($x, $ty) = ($ty,bmod($x,$ty));
-    }
-  $x;
+  return $x->bnan() if ($x->{sign} eq $nan) || ($ty->{sign} eq $nan);
+  my $method = ref($x) . '::bgcd';
+  no strict 'refs';
+  $x * $ty / &$method($x,$ty);
   }
 
 ###############################################################################
-# this method return 0 if the object can be modified, or 1 for not
+# this method returns 0 if the object can be modified, or 1 if not.
 # We use a fast constant sub() here, to avoid costly calls. Subclasses
 # may override it with special code (f.i. Math::BigInt::Constant does so)
 
@@ -2699,9 +2639,11 @@ sub modify () { 0; }
 1;
 __END__
 
+=pod
+
 =head1 NAME
 
-Math::BigInt - Arbitrary size integer math package
+Math::BigInt - Arbitrary size integer/float math package
 
 =head1 SYNOPSIS
 
@@ -2713,8 +2655,13 @@ Math::BigInt - Arbitrary size integer math package
 
   use Math::BigInt lib => 'GMP';
 
+  my $str = '1234567890';
+  my @values = (64,74,18);
+  my $n = 1; my $sign = '-';
+
   # Number creation    
   $x = Math::BigInt->new($str);                # defaults to 0
+  $y = $x->copy();                     # make a true copy
   $nan  = Math::BigInt->bnan();        # create a NotANumber
   $zero = Math::BigInt->bzero();       # create a +0
   $inf = Math::BigInt->binf();         # create a +inf
@@ -2733,10 +2680,10 @@ Math::BigInt - Arbitrary size integer math package
   $x->is_even();       # if $x is even
   $x->is_pos();                # if $x >= 0
   $x->is_neg();                # if $x <  0
-  $x->is_inf(sign);    # if $x is +inf, or -inf (sign is default '+')
+  $x->is_inf($sign);   # if $x is +inf, or -inf (sign is default '+')
   $x->is_int();                # if $x is an integer (not a float)
 
-  # comparing and digit/sign extration
+  # comparing and digit/sign extraction
   $x->bcmp($y);                # compare numbers (undef,<0,=0,>0)
   $x->bacmp($y);       # compare absolutely (undef,<0,=0,>0)
   $x->sign();          # return the sign, either +,- or NaN
@@ -2745,7 +2692,7 @@ Math::BigInt - Arbitrary size integer math package
 
   # The following all modify their first argument. If you want to preserve
   # $x, use $z = $x->copy()->bXXX($y); See under L<CAVEATS> for why this is
-  # neccessary when mixing $a = $b assigments with non-overloaded math.
+  # necessary when mixing $a = $b assignments with non-overloaded math.
 
   $x->bzero();         # set $x to 0
   $x->bnan();          # set $x to NaN
@@ -2787,8 +2734,8 @@ Math::BigInt - Arbitrary size integer math package
   $x->bfac();             # factorial of $x (1*2*3*4*..$x)
 
   $x->round($A,$P,$mode);  # round to accuracy or precision using mode $mode
-  $x->bround($N);          # accuracy: preserve $N digits
-  $x->bfround($N);         # round to $Nth digit, no-op for BigInts
+  $x->bround($n);         # accuracy: preserve $n digits
+  $x->bfround($n);        # round to $nth digit, no-op for BigInts
 
   # The following do not modify their arguments in BigInt (are no-ops),
   # but do so in BigFloat:
@@ -2798,12 +2745,14 @@ Math::BigInt - Arbitrary size integer math package
   
   # The following do not modify their arguments:
 
-  bgcd(@values);          # greatest common divisor (no OO style)
-  blcm(@values);          # lowest common multiplicator (no OO style)
+  # greatest common divisor (no OO style)
+  my $gcd = Math::BigInt::bgcd(@values);
+  # lowest common multiplicator (no OO style)
+  my $lcm = Math::BigInt::blcm(@values);       
  
   $x->length();                   # return number of digits in number
-  ($x,$f) = $x->length();  # length of number and length of fraction part,
-                          # latter is always 0 digits long for BigInt's
+  ($xl,$f) = $x->length(); # length of number and length of fraction part,
+                          # latter is always 0 digits long for BigInts
 
   $x->exponent();         # return exponent as BigInt
   $x->mantissa();         # return (signed) mantissa as BigInt
@@ -2813,8 +2762,8 @@ Math::BigInt - Arbitrary size integer math package
   $x->numify();                   # return as scalar (might overflow!)
   
   # conversation to string (do not modify their argument)
-  $x->bstr();             # normalized string
-  $x->bsstr();            # normalized string in scientific notation
+  $x->bstr();             # normalized string (e.g. '3')
+  $x->bsstr();            # norm. string in scientific notation (e.g. '3E0')
   $x->as_hex();                   # as signed hexadecimal string with prefixed 0x
   $x->as_bin();                   # as signed binary string with prefixed 0b
 
@@ -2826,13 +2775,15 @@ Math::BigInt - Arbitrary size integer math package
   $x->accuracy($n);       # set A $x to $n
 
   # Global methods
-  Math::BigInt->precision(); # get/set global P for all BigInt objects
-  Math::BigInt->accuracy();  # get/set global A for all BigInt objects
-  Math::BigInt->config();    # return hash containing configuration
+  Math::BigInt->precision();   # get/set global P for all BigInt objects
+  Math::BigInt->accuracy();    # get/set global A for all BigInt objects
+  Math::BigInt->round_mode();  # get/set global round mode, one of
+                               # 'even', 'odd', '+inf', '-inf', 'zero' or 'trunc'
+  Math::BigInt->config();      # return hash containing configuration
 
 =head1 DESCRIPTION
 
-All operators (inlcuding basic math operations) are overloaded if you
+All operators (including basic math operations) are overloaded if you
 declare your big integers as
 
   $i = new Math::BigInt '123_456_789_123_456_789';
@@ -2872,19 +2823,20 @@ object from the input.
 
 =item Output
 
-Output values are BigInt objects (normalized), except for bstr(), which
-returns a string in normalized form.
+Output values are BigInt objects (normalized), except for the methods which
+return a string (see L<SYNOPSIS>).
+
 Some routines (C<is_odd()>, C<is_even()>, C<is_zero()>, C<is_one()>,
-C<is_nan()>) return true or false, while others (C<bcmp()>, C<bacmp()>)
-return either undef, <0, 0 or >0 and are suited for sort.
+C<is_nan()>, etc.) return true or false, while others (C<bcmp()>, C<bacmp()>)
+return either undef (if NaN is involved), <0, 0 or >0 and are suited for sort.
 
 =back
 
 =head1 METHODS
 
 Each of the methods below (except config(), accuracy() and precision())
-accepts three additional parameters. These arguments $A, $P and $R are
-accuracy, precision and round_mode. Please see the section about
+accepts three additional parameters. These arguments C<$A>, C<$P> and C<$R>
+are C<accuracy>, C<precision> and C<round_mode>. Please see the section about
 L<ACCURACY and PRECISION> for more information.
 
 =head2 config
@@ -2919,7 +2871,7 @@ appropriate information.
                        even
        version         version number of the class you used
                        1.61
-       div_scale       Fallback acccuracy for div
+       div_scale       Fallback accuracy for div
                        40
        trap_nan        If true, traps creation of NaN via croak()
                        1
@@ -2939,11 +2891,26 @@ Example:
 
        $x->accuracy(5);                # local for $x
        CLASS->accuracy(5);             # global for all members of CLASS
-       $A = $x->accuracy();            # read out
-       $A = CLASS->accuracy();         # read out
+                                       # Note: This also applies to new()!
+
+       $A = $x->accuracy();            # read out accuracy that affects $x
+       $A = CLASS->accuracy();         # read out global accuracy
 
 Set or get the global or local accuracy, aka how many significant digits the
-results have. 
+results have. If you set a global accuracy, then this also applies to new()!
+
+Warning! The accuracy I<sticks>, e.g. once you created a number under the
+influence of C<< CLASS->accuracy($A) >>, all results from math operations with
+that number will also be rounded. 
+
+In most cases, you should probably round the results explicitly using one of
+L<round()>, L<bround()> or L<bfround()> or by passing the desired accuracy
+to the math operation as additional parameter:
+
+        my $x = Math::BigInt->new(30000);
+        my $y = Math::BigInt->new(7);
+        print scalar $x->copy()->bdiv($y, 2);          # print 4300
+        print scalar $x->copy()->bdiv($y)->bround(2);  # print 4300
 
 Please see the section about L<ACCURACY AND PRECISION> for further details.
 
@@ -2958,7 +2925,7 @@ represents the accuracy that will be in effect for $x:
 
        $y = Math::BigInt->new(1234567);        # unrounded
        print Math::BigInt->accuracy(4),"\n";   # set 4, print 4
-       $x = Math::BigInt->new(123456);         # will be automatically rounded
+       $x = Math::BigInt->new(123456);         # $x will be automatically rounded!
        print "$x $y\n";                        # '123500 1234567'
        print $x->accuracy(),"\n";              # will be 4
        print $y->accuracy(),"\n";              # also 4, since global is 4
@@ -2973,35 +2940,46 @@ Math::BigInt.
 
 =head2 precision
 
-       $x->precision(-2);              # local for $x, round right of the dot
-       $x->precision(2);               # ditto, but round left of the dot
-       CLASS->accuracy(5);             # global for all members of CLASS
-       CLASS->precision(-5);           # ditto
-       $P = CLASS->precision();        # read out
-       $P = $x->precision();           # read out
+       $x->precision(-2);      # local for $x, round at the second digit right of the dot
+       $x->precision(2);       # ditto, round at the second digit left of the dot
 
-Set or get the global or local precision, aka how many digits the result has
-after the dot (or where to round it when passing a positive number). In
-Math::BigInt, passing a negative number precision has no effect since no
-numbers have digits after the dot.
+       CLASS->precision(5);    # Global for all members of CLASS
+                               # This also applies to new()!
+       CLASS->precision(-5);   # ditto
+
+       $P = CLASS->precision();        # read out global precision 
+       $P = $x->precision();           # read out precision that affects $x
+
+Note: You probably want to use L<accuracy()> instead. With L<accuracy> you
+set the number of digits each result should have, with L<precision> you
+set the place where to round!
+
+C<precision()> sets or gets the global or local precision, aka at which digit
+before or after the dot to round all results. A set global precision also
+applies to all newly created numbers!
+
+In Math::BigInt, passing a negative number precision has no effect since no
+numbers have digits after the dot. In L<Math::BigFloat>, it will round all
+results to P digits after the dot.
 
 Please see the section about L<ACCURACY AND PRECISION> for further details.
 
-Value must be greater than zero. Pass an undef value to disable it:
+Pass an undef value to disable it:
 
        $x->precision(undef);
        Math::BigInt->precision(undef);
 
 Returns the current precision. For C<$x->precision()> it will return either the
 local precision of $x, or if not defined, the global. This means the return
-value represents the accuracy that will be in effect for $x:
+value represents the prevision that will be in effect for $x:
 
        $y = Math::BigInt->new(1234567);        # unrounded
        print Math::BigInt->precision(4),"\n";  # set 4, print 4
        $x = Math::BigInt->new(123456);         # will be automatically rounded
+       print $x;                               # print "120000"!
 
-Note: Works also for subclasses like Math::BigFloat. Each class has it's own
-globals separated from Math::BigInt, but it is possible to subclass
+Note: Works also for subclasses like L<Math::BigFloat>. Each class has its
+own globals separated from Math::BigInt, but it is possible to subclass
 Math::BigInt and make the globals of the subclass aliases to the ones from
 Math::BigInt.
 
@@ -3090,7 +3068,7 @@ If used on an object, it will set it to one:
        $x->is_inf();                   # true if +inf
        $x->is_inf('-');                # true if -inf (sign is default '+')
 
-These methods all test the BigInt for beeing one specific value and return
+These methods all test the BigInt for being one specific value and return
 true or false depending on the input. These are faster than doing something
 like:
 
@@ -3098,16 +3076,16 @@ like:
 
 =head2 is_pos()/is_neg()
        
-       $x->is_pos();                   # true if >= 0
-       $x->is_neg();                   # true if <  0
+       $x->is_pos();                   # true if > 0
+       $x->is_neg();                   # true if < 0
 
 The methods return true if the argument is positive or negative, respectively.
 C<NaN> is neither positive nor negative, while C<+inf> counts as positive, and
-C<-inf> is negative. A C<zero> is positive.
+C<-inf> is negative. A C<zero> is neither positive nor negative.
 
 These methods are only testing the sign, and not the value.
 
-C<is_positive()> and C<is_negative()> are aliase to C<is_pos()> and
+C<is_positive()> and C<is_negative()> are aliases to C<is_pos()> and
 C<is_neg()>, respectively. C<is_positive()> and C<is_negative()> were
 introduced in v1.36, while C<is_pos()> and C<is_neg()> were only introduced
 in v1.68.
@@ -3142,6 +3120,14 @@ Compares $x with $y while ignoring their. Returns -1, 0, 1 or undef.
 
 Return the sign, of $x, meaning either C<+>, C<->, C<-inf>, C<+inf> or NaN.
 
+If you want $x to have a certain sign, use one of the following methods:
+
+       $x->babs();             # '+'
+       $x->babs()->bneg();     # '-'
+       $x->bnan();             # 'NaN'
+       $x->binf();             # '+inf'
+       $x->binf('-');          # '-inf'
+
 =head2 digit
 
        $x->digit($n);          # return the nth digit, counting from right
@@ -3354,7 +3340,7 @@ v1.22, while C<as_int()> was only introduced in v1.68.
 
        $x->bstr();
 
-Returns a normalized string represantation of C<$x>.
+Returns a normalized string representation of C<$x>.
 
 =head2 bsstr
 
@@ -3525,7 +3511,7 @@ versions <= 5.7.2) is like this:
       result has at most max(scale, length(dividend), length(divisor)) digits
     Actual code:
       scale = max(scale, length(dividend)-1,length(divisor)-1);
-      scale += length(divisior) - length(dividend);
+      scale += length(divisor) - length(dividend);
     So for lx = 3, ly = 9, scale = 10, scale will actually be 16 (10+9-3).
     Actually, the 'difference' added to the scale is calculated from the
     number of "significant digits" in dividend and divisor, which is derived
@@ -3564,7 +3550,7 @@ This is how it works now:
   * to find out the current global P, use C<< Math::SomeClass->precision() >>
   * use C<< $x->accuracy() >> respective C<< $x->precision() >> for the local
     setting of C<< $x >>.
-  * Please note that C<< $x->accuracy() >> respecive C<< $x->precision() >>
+  * Please note that C<< $x->accuracy() >> respective C<< $x->precision() >>
     return eventually defined global A or P, when C<< $x >>'s A or P is not
     set.
 
@@ -3610,7 +3596,7 @@ This is how it works now:
     be automatically cleared.
   * If two objects are involved in an operation, and one of them has A in
     effect, and the other P, this results in an error (NaN).
-  * A takes precendence over P (Hint: A comes before P).
+  * A takes precedence over P (Hint: A comes before P).
     If neither of them is defined, nothing is used, i.e. the result will have
     as many digits as it can (with an exception for fdiv/fsqrt) and will not
     be rounded.
@@ -3628,7 +3614,7 @@ This is how it works now:
     + never round (this is the default):
       This is done by setting A and P to undef. No math operation
       will round the result, with fdiv() and fsqrt() as exceptions to guard
-      against overflows. You must explicitely call bround(), bfround() or
+      against overflows. You must explicitly call bround(), bfround() or
       round() (the latter with parameters).
       Note: Once you have rounded a number, the settings will 'stick' on it
       and 'infect' all other numbers engaged in math operations with it, since
@@ -3721,12 +3707,58 @@ This is how it works now:
 
 =back
 
+=head1 Infinity and Not a Number
+
+While BigInt has extensive handling of inf and NaN, certain quirks remain.
+
+=over 2
+
+=item oct()/hex()
+
+These perl routines currently (as of Perl v.5.8.6) cannot handle passed
+inf.
+
+       te@linux:~> perl -wle 'print 2 ** 3333'
+       inf
+       te@linux:~> perl -wle 'print 2 ** 3333 == 2 ** 3333'
+       1
+       te@linux:~> perl -wle 'print oct(2 ** 3333)'
+       0
+       te@linux:~> perl -wle 'print hex(2 ** 3333)'
+       Illegal hexadecimal digit 'i' ignored at -e line 1.
+       0
+
+The same problems occur if you pass them Math::BigInt->binf() objects. Since
+overloading these routines is not possible, this cannot be fixed from BigInt.
+
+=item ==, !=, <, >, <=, >= with NaNs
+
+BigInt's bcmp() routine currently returns undef to signal that a NaN was
+involved in a comparison. However, the overload code turns that into
+either 1 or '' and thus operations like C<< NaN != NaN >> might return
+wrong values.
+
+=item log(-inf)
+
+C<< log(-inf) >> is highly weird. Since log(-x)=pi*i+log(x), then
+log(-inf)=pi*i+inf. However, since the imaginary part is finite, the real
+infinity "overshadows" it, so the number might as well just be infinity.
+However, the result is a complex number, and since BigInt/BigFloat can only
+have real numbers as results, the result is NaN.
+
+=item exp(), cos(), sin(), atan2()
+
+These all might have problems handling infinity right.
+=back
+
 =head1 INTERNALS
 
 The actual numbers are stored as unsigned big integers (with seperate sign).
+
 You should neither care about nor depend on the internal representation; it
-might change without notice. Use only method calls like C<< $x->sign(); >>
-instead relying on the internal hash keys like in C<< $x->{sign}; >>. 
+might change without notice. Use B<ONLY> method calls like C<< $x->sign(); >>
+instead relying on the internal representation.
 
 =head2 MATH LIBRARY
 
@@ -3745,20 +3777,21 @@ Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc:
        use Math::BigInt lib => 'Foo,Math::BigInt::Bar';
 
 Since Math::BigInt::GMP is in almost all cases faster than Calc (especially in
-cases involving really big numbers, where it is B<much> faster), and there is
+math involving really big numbers, where it is B<much> faster), and there is
 no penalty if Math::BigInt::GMP is not installed, it is a good idea to always
 use the following:
 
        use Math::BigInt lib => 'GMP';
 
 Different low-level libraries use different formats to store the
-numbers. You should not depend on the number having a specific format.
+numbers. You should B<NOT> depend on the number having a specific format
+internally.
 
 See the respective math library module documentation for further details.
 
 =head2 SIGN
 
-The sign is either '+', '-', 'NaN', '+inf' or '-inf' and stored seperately.
+The sign is either '+', '-', 'NaN', '+inf' or '-inf'.
 
 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
@@ -3893,7 +3926,7 @@ more time then the actual addition.
 With a technique called copy-on-write, the cost of copying with overload could
 be minimized or even completely avoided. A test implementation of COW did show
 performance gains for overloaded math, but introduced a performance loss due
-to a constant overhead for all other operatons. So Math::BigInt does currently
+to a constant overhead for all other operations. So Math::BigInt does currently
 not COW.
 
 The rewritten version of this module (vs. v0.01) is slower on certain
@@ -4100,7 +4133,7 @@ Additionally, the following still works:
 
 There is now a C<bsstr()> method to get the string in scientific notation aka
 C<1e+2> instead of C<100>. Be advised that overloaded 'eq' always uses bstr()
-for comparisation, but Perl will represent some numbers as 100 and others
+for comparison, but Perl will represent some numbers as 100 and others
 as 1e+308. If in doubt, convert both arguments to Math::BigInt before 
 comparing them as strings:
 
@@ -4114,10 +4147,13 @@ comparing them as strings:
        $y = Math::BigInt->new($y);
        ok ($x,$y);                     # okay
 
-Alternatively, simple use C<< <=> >> for comparisations, this will get it
+Alternatively, simple use C<< <=> >> for comparisons, this will get it
 always right. There is not yet a way to get a number automatically represented
 as a string that matches exactly the way Perl represents it.
 
+See also the section about L<Infinity and Not a Number> for problems in
+comparing NaNs.
+
 =item int()
 
 C<int()> will return (at least for Perl v5.7.1 and up) another BigInt, not a 
@@ -4128,14 +4164,25 @@ Perl scalar:
        $x = Math::BigFloat->new(123.45);
        $y = int($x);                           # BigInt 123
 
-In all Perl versions you can use C<as_number()> for the same effect:
+In all Perl versions you can use C<as_number()> or C<as_int> for the same
+effect:
 
        $x = Math::BigFloat->new(123.45);
        $y = $x->as_number();                   # BigInt 123
+       $y = $x->as_int();                      # ditto
 
 This also works for other subclasses, like Math::String.
 
-It is yet unlcear whether overloaded int() should return a scalar or a BigInt.
+It is yet unclear whether overloaded int() should return a scalar or a BigInt.
+
+If you want a real Perl scalar, use C<numify()>:
+
+       $y = $x->numify();                      # 123 as scalar
+
+This is seldom necessary, though, because this is done automatically, like
+when you access an array:
+
+       $z = $array[$x];                        # does work automatically
 
 =item length
 
@@ -4156,7 +4203,7 @@ The following will probably not do what you expect:
        print $c->bdiv(10000),"\n";
 
 It prints both quotient and remainder since print calls C<bdiv()> in list
-context. Also, C<bdiv()> will modify $c, so be carefull. You probably want
+context. Also, C<bdiv()> will modify $c, so be careful. You probably want
 to use
        
        print $c / 10000,"\n";
@@ -4185,7 +4232,7 @@ manpage), and the equation
 holds true for any $x and $y, which justifies calling the two return
 values of bdiv() the quotient and remainder. The only exception to this rule
 are when $y == 0 and $x is negative, then the remainder will also be
-negative. See below under "infinity handling" for the reasoning behing this.
+negative. See below under "infinity handling" for the reasoning behind this.
 
 Perl's 'use integer;' changes the behaviour of % and / for scalars, but will
 not change BigInt's way to do things. This is because under 'use integer' Perl
@@ -4289,9 +4336,6 @@ since overload calls C<sub($x,0,1);> instead of C<neg($x)>. The first variant
 needs to preserve $x since it does not know that it later will get overwritten.
 This makes a copy of $x and takes O(N), but $x->bneg() is O(1).
 
-With Copy-On-Write, this issue would be gone, but C-o-W is not implemented
-since it is slower for all other things.
-
 =item Mixing different object types
 
 In Perl you will get a floating point value if you do one of the following:
@@ -4396,11 +4440,11 @@ subclass files and benchmarks.
 =head1 AUTHORS
 
 Original code by Mark Biggar, overloaded interface by Ilya Zakharevich.
-Completely rewritten by Tels http://bloodgate.com in late 2000, 2001, 2002
-and still at it in 2003.
+Completely rewritten by Tels http://bloodgate.com in late 2000, 2001 - 2004
+and still at it in 2005.
 
 Many people contributed in one or more ways to the final beast, see the file
-CREDITS for an (uncomplete) list. If you miss your name, please drop me a
+CREDITS for an (incomplete) list. If you miss your name, please drop me a
 mail. Thank you!
 
 =cut