According to Tels our M::BI is _better_ than the 1.64 in CPAN.
[p5sagit/p5-mst-13.2.git] / lib / Math / BigInt.pm
index 77f3343..1625d1c 100644 (file)
@@ -18,7 +18,7 @@ package Math::BigInt;
 my $class = "Math::BigInt";
 require 5.005;
 
-$VERSION = '1.58';
+$VERSION = '1.64_01';
 use Exporter;
 @ISA =       qw( Exporter );
 @EXPORT_OK = qw( objectify _swap bgcd blcm); 
@@ -67,7 +67,7 @@ use overload
 
 '<=>'  =>      sub { $_[2] ?
                       ref($_[0])->bcmp($_[1],$_[0]) : 
-                      ref($_[0])->bcmp($_[0],$_[1])},
+                      $_[0]->bcmp($_[1])},
 'cmp'  =>      sub {
          $_[2] ? 
                "$_[1]" cmp $_[0]->bstr() :
@@ -234,12 +234,12 @@ sub accuracy
     return $a;                         # shortcut
     }
 
-  if (ref($x))
-    {
-    # $object->accuracy() or fallback to global
-    return $x->{_a} || ${"${class}::accuracy"};
-    }
-  return ${"${class}::accuracy"};
+  my $r;
+  # $object->accuracy() or fallback to global
+  $r = $x->{_a} if ref($x);
+  # but don't return global undef, when $x's accuracy is 0!
+  $r = ${"${class}::accuracy"} if !defined $r;
+  $r;
   } 
 
 sub precision
@@ -273,12 +273,12 @@ sub precision
     return $p;                         # shortcut
     }
 
-  if (ref($x))
-    {
-    # $object->precision() or fallback to global
-    return $x->{_p} || ${"${class}::precision"};
-    }
-  return ${"${class}::precision"};
+  my $r;
+  # $object->precision() or fallback to global
+  $r = $x->{_p} if ref($x);
+  # but don't return global undef, when $x's precision is 0!
+  $r = ${"${class}::precision"} if !defined $r;
+  $r;
   } 
 
 sub config
@@ -406,13 +406,13 @@ sub new
   my $self = bless {}, $class;
 
   # shortcut for "normal" numbers
-  if ((!ref $wanted) && ($wanted =~ /^([+-]?)[1-9][0-9]*$/))
+  if ((!ref $wanted) && ($wanted =~ /^([+-]?)[1-9][0-9]*\z/))
     {
     $self->{sign} = $1 || '+';
     my $ref = \$wanted;
     if ($wanted =~ /^[+-]/)
      {
-      # remove sign without touching wanted
+      # remove sign without touching wanted to make it work with constants
       my $t = $wanted; $t =~ s/^[+-]//; $ref = \$t;
       }
     $self->{value} = $CALC->_new($ref);
@@ -585,12 +585,20 @@ sub bzero
   $self->{sign} = '+';
   if (@_ > 0)
     {
-    $self->{_a} = $_[0]
-     if (defined $self->{_a} && defined $_[0] && $_[0] > $self->{_a});
-    $self->{_p} = $_[1]
-     if (defined $self->{_p} && defined $_[1] && $_[1] < $self->{_p});
+    if (@_ > 3)
+      {
+      # call like: $x->bzero($a,$p,$r,$y);
+      ($self,$self->{_a},$self->{_p}) = $self->_find_round_parameters(@_);
+      }
+    else
+      {
+      $self->{_a} = $_[0]
+       if ( (!defined $self->{_a}) || (defined $_[0] && $_[0] > $self->{_a}));
+      $self->{_p} = $_[1]
+       if ( (!defined $self->{_p}) || (defined $_[1] && $_[1] > $self->{_p}));
+      }
     }
-  return $self;
+  $self;
   }
 
 sub bone
@@ -600,7 +608,7 @@ sub bone
   my $self = shift;
   my $sign = shift; $sign = '+' if !defined $sign || $sign ne '-';
   $self = $class if !defined $self;
-  
   if (!ref($self))
     {
     my $c = $self; $self = {}; bless $self, $c;
@@ -621,12 +629,20 @@ sub bone
   $self->{sign} = $sign;
   if (@_ > 0)
     {
-    $self->{_a} = $_[0]
-     if (defined $self->{_a} && defined $_[0] && $_[0] > $self->{_a});
-    $self->{_p} = $_[1]
-     if (defined $self->{_p} && defined $_[1] && $_[1] < $self->{_p});
+    if (@_ > 3)
+      {
+      # call like: $x->bone($sign,$a,$p,$r,$y);
+      ($self,$self->{_a},$self->{_p}) = $self->_find_round_parameters(@_);
+      }
+    else
+      {
+      $self->{_a} = $_[0]
+       if ( (!defined $self->{_a}) || (defined $_[0] && $_[0] > $self->{_a}));
+      $self->{_p} = $_[1]
+       if ( (!defined $self->{_p}) || (defined $_[1] && $_[1] > $self->{_p}));
+      }
     }
-  return $self;
+  $self;
   }
 
 ##############################################################################
@@ -646,9 +662,7 @@ sub bsstr
     return 'inf';                                      # +inf
     }
   my ($m,$e) = $x->parts();
-  # e can only be positive
-  my $sign = 'e+';     
-  # MBF: my $s = $e->{sign}; $s = '' if $s eq '-'; my $sep = 'e'.$s;
+  my $sign = 'e+'; # e can only be positive
   return $m->bstr().$sign.$e->bstr();
   }
 
@@ -671,7 +685,8 @@ sub numify
   {
   # Make a "normal" scalar from a BigInt object
   my $x = shift; $x = $class->new($x) unless ref $x;
-  return $x->{sign} if $x->{sign} !~ /^[+-]$/;
+
+  return $x->bstr() if $x->{sign} !~ /^[+-]$/;
   my $num = $CALC->_num($x->{value});
   return -$num if $x->{sign} eq '-';
   $num;
@@ -844,7 +859,18 @@ sub bcmp
   {
   # Compares 2 values.  Returns one of undef, <0, =0, >0. (suitable for sort)
   # (BINT or num_str, BINT or num_str) return cond_code
-  my ($self,$x,$y) = objectify(2,@_);
+  
+  # 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,@_);
+    }
+
+  return $upgrade->bcmp($x,$y) if defined $upgrade &&
+    ((!$x->isa($self)) || (!$y->isa($self)));
 
   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
     {
@@ -860,13 +886,9 @@ sub bcmp
   return 1 if $x->{sign} eq '+' && $y->{sign} eq '-';  # does also 0 <=> -y
   return -1 if $x->{sign} eq '-' && $y->{sign} eq '+';  # does also -x <=> 0 
 
-  # shortcut
-  my $xz = $x->is_zero();
-  my $yz = $y->is_zero();
-  return 0 if $xz && $yz;                               # 0 <=> 0
-  return -1 if $xz && $y->{sign} eq '+';                # 0 <=> +y
-  return 1 if $yz && $x->{sign} eq '+';                 # +x <=> 0
-  
+  # have same sign, so compare absolute values. Don't make tests for zero here
+  # because it's actually slower than testin in Calc (especially w/ Pari et al)
+
   # post-normalized compare for internal use (honors signs)
   if ($x->{sign} eq '+') 
     {
@@ -875,7 +897,7 @@ sub bcmp
     }
 
   # $x && $y both < 0
-  $CALC->_acmp($y->{value},$x->{value});       # swaped (lib does only 0,1,-1)
+  $CALC->_acmp($y->{value},$x->{value});       # swaped (lib returns 0,1,-1)
   }
 
 sub bacmp 
@@ -883,8 +905,18 @@ sub bacmp
   # Compares 2 values, ignoring their signs. 
   # Returns one of undef, <0, =0, >0. (suitable for sort)
   # (BINT, BINT) return cond_code
-  my ($self,$x,$y) = objectify(2,@_);
   
+  # 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,@_);
+    }
+
+  return $upgrade->bacmp($x,$y) if defined $upgrade &&
+    ((!$x->isa($self)) || (!$y->isa($self)));
+
   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/))
     {
     # handle +-inf and NaN
@@ -899,7 +931,14 @@ sub badd
   {
   # add second arg (BINT or string) to first (BINT) (modifies first)
   # return result as BINT
-  my ($self,$x,$y,@r) = objectify(2,@_);
+
+  # 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,@_);
+    }
 
   return $x if $x->modify('badd');
   return $upgrade->badd($x,$y,@r) if defined $upgrade &&
@@ -954,14 +993,22 @@ sub badd
       $x->{sign} = $sx;
       }
     }
-  $x->round(@r);
+  $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+  $x;
   }
 
 sub bsub 
   {
   # (BINT or num_str, BINT or num_str) return num_str
   # subtract second arg from first, modify first
-  my ($self,$x,$y,@r) = objectify(2,@_);
+  
+  # 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,@_);
+    }
 
   return $x if $x->modify('bsub');
 
@@ -971,7 +1018,8 @@ sub bsub
 
   if ($y->is_zero())
     { 
-    return $x->round(@r);
+    $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+    return $x;
     }
 
   $y->{sign} =~ tr/+\-/-+/;    # does nothing for NaN
@@ -989,13 +1037,15 @@ sub binc
   if ($x->{sign} eq '+')
     {
     $x->{value} = $CALC->_inc($x->{value});
-    return $x->round($a,$p,$r);
+    $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+    return $x;
     }
   elsif ($x->{sign} eq '-')
     {
     $x->{value} = $CALC->_dec($x->{value});
     $x->{sign} = '+' if $CALC->_is_zero($x->{value}); # -1 +1 => -0 => +0
-    return $x->round($a,$p,$r);
+    $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+    return $x;
     }
   # inf, nan handling etc
   $x->badd($self->__one(),$a,$p,$r);           # badd does round
@@ -1014,13 +1064,15 @@ sub bdec
     $x->{value} = $CALC->_inc($x->{value});
     $x->{sign} = '-' if $zero;                 # 0 => 1 => -1
     $x->{sign} = '+' if $CALC->_is_zero($x->{value}); # -1 +1 => -0 => +0
-    return $x->round($a,$p,$r);
+    $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+    return $x;
     }
   # > 0
   elsif ($x->{sign} eq '+')
     {
     $x->{value} = $CALC->_dec($x->{value});
-    return $x->round($a,$p,$r);
+    $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+    return $x;
     }
   # inf, nan handling etc
   $x->badd($self->__one('-'),$a,$p,$r);                        # badd does round
@@ -1206,7 +1258,14 @@ sub bmul
   { 
   # multiply two numbers -- stolen from Knuth Vol 2 pg 233
   # (BINT or num_str, BINT or num_str) return BINT
-  my ($self,$x,$y,@r) = objectify(2,@_);
+
+  # 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,@_);
+    }
   
   return $x if $x->modify('bmul');
 
@@ -1233,7 +1292,9 @@ 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);
+
+  $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+  $x;
   }
 
 sub _div_inf
@@ -1254,7 +1315,7 @@ sub _div_inf
   # x / +-inf => 0, remainder x (works even if x == 0)
   if ($y->{sign} =~ /^[+-]inf$/)
     {
-    my $t = $x->copy();                # binf clobbers up $x
+    my $t = $x->copy();                # bzero clobbers up $x
     return wantarray ? ($x->bzero(),$t) : $x->bzero()
     }
   
@@ -1285,14 +1346,20 @@ sub bdiv
   {
   # (dividend: BINT or num_str, divisor: BINT or num_str) return 
   # (BINT,BINT) (quo,rem) or BINT (only rem)
-  my ($self,$x,$y,@r) = objectify(2,@_);
+  
+  # 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,@_);
+    } 
 
   return $x if $x->modify('bdiv');
 
   return $self->_div_inf($x,$y)
    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
 
-  #print "mbi bdiv $x $y\n";
   return $upgrade->bdiv($upgrade->new($x),$y,@r)
    if defined $upgrade && !$y->isa($self);
 
@@ -1337,6 +1404,8 @@ sub bdiv
     my $rem = $self->bzero(); 
     ($x->{value},$rem->{value}) = $CALC->_div($x->{value},$y->{value});
     $x->{sign} = '+' if $CALC->_is_zero($x->{value});
+    $rem->{_a} = $x->{_a};
+    $rem->{_p} = $x->{_p};
     $x->round(@r); 
     if (! $CALC->_is_zero($rem->{value}))
       {
@@ -1347,13 +1416,14 @@ sub bdiv
       {
       $rem->{sign} = '+';                      # dont leave -0
       }
-    $rem->round(@r);
-    return ($x,$rem);
+    return ($x,$rem->round(@r));
     }
 
   $x->{value} = $CALC->_div($x->{value},$y->{value});
   $x->{sign} = '+' if $CALC->_is_zero($x->{value});
-  $x->round(@r); 
+
+  $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+  $x;
   }
 
 ###############################################################################
@@ -1363,14 +1433,23 @@ sub bmod
   {
   # modulus (or remainder)
   # (BINT or num_str, BINT or num_str) return BINT
-  my ($self,$x,$y,@r) = objectify(2,@_);
+  
+  # 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,@_);
+    }
 
   return $x if $x->modify('bmod');
   $r[3] = $y;                                  # no push!
   if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero())
     {
     my ($d,$r) = $self->_div_inf($x,$y);
-    return $r->round(@r);
+    $x->{sign} = $r->{sign};
+    $x->{value} = $r->{value};
+    return $x->round(@r);
     }
 
   if ($CALC->can('_mod'))
@@ -1383,8 +1462,8 @@ sub bmod
       $x->{sign} = $y->{sign};
       if ($xsign ne $y->{sign})
         {
-        my $t = [ @{$x->{value}} ];                    # copy $x
-        $x->{value} = [ @{$y->{value}} ];              # copy $y to $x
+        my $t = $CALC->_copy($x->{value});             # copy $x
+        $x->{value} = $CALC->_copy($y->{value});       # copy $y to $x
         $x->{value} = $CALC->_sub($y->{value},$t,1);   # $y-$x
         }
       }
@@ -1392,7 +1471,8 @@ sub bmod
       {
       $x->{sign} = '+';                                # dont leave -0
       }
-    return $x->round(@r);
+    $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+    return $x;
     }
   my ($t,$rem) = $self->bdiv($x->copy(),$y,@r);        # slow way (also rounds)
   # modify in place
@@ -1405,53 +1485,81 @@ sub bmod
 
 sub bmodinv
   {
-  # modular inverse.  given a number which is (hopefully) relatively
+  # Modular inverse.  given a number which is (hopefully) relatively
   # prime to the modulus, calculate its inverse using Euclid's
-  # alogrithm.  if the number is not relatively prime to the modulus
+  # alogrithm.  If the number is not relatively prime to the modulus
   # (i.e. their gcd is not one) then NaN is returned.
 
-  my ($self,$num,$mod,@r) = objectify(2,@_);
+  # 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,@_);
+    }
 
-  return $num if $num->modify('bmodinv');
+  return $x if $x->modify('bmodinv');
 
-  return $num->bnan()
-       if ($mod->{sign} ne '+'                         # -, NaN, +inf, -inf
-         || $num->is_zero()                            # or num == 0
-        || $num->{sign} !~ /^[+-]$/                    # or num NaN, inf, -inf
+  return $x->bnan()
+        if ($y->{sign} ne '+'                           # -, NaN, +inf, -inf
+         || $x->is_zero()                               # or num == 0
+         || $x->{sign} !~ /^[+-]$/                      # or num NaN, inf, -inf
         );
-  return $num                        # i.e., NaN or some kind of infinity,
-      if ($num->{sign} !~ /^[+-]$/);
+
+  # put least residue into $x if $x was negative, and thus make it positive
+  $x->bmod($y) if $x->{sign} eq '-';
 
   if ($CALC->can('_modinv'))
     {
-    $num->{value} = $CALC->_modinv($mod->{value});
-    return $num;
+    my $sign;
+    ($x->{value},$sign) = $CALC->_modinv($x->{value},$y->{value});
+    $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;
     }
-
-  # the remaining case, nonpositive case, $num < 0, is addressed below.
-
   my ($u, $u1) = ($self->bzero(), $self->bone());
-  my ($a, $b) = ($mod->copy(), $num->copy());
-
-  # put least residue into $b if $num was negative
-  $b->bmod($mod) if $b->{sign} eq '-';
-
-  # Euclid's Algorithm
-  while (!$b->is_zero())
+  my ($a, $b) = ($y->copy(), $x->copy());
+
+  # first step need always be done since $num (and thus $b) is never 0
+  # Note that the loop is aligned so that the check occurs between #2 and #1
+  # thus saving us one step #2 at the loop end. Typical loop count is 1. Even
+  # a case with 28 loops still gains about 3% with this layout.
+  my $q;
+  ($a, $q, $b) = ($b, $a->bdiv($b));                    # step #1
+  # Euclid's Algorithm (calculate GCD of ($a,$b) in $a and also calculate
+  # two values in $u and $u1, we use only $u1 afterwards)
+  my $sign = 1;                                         # flip-flop
+  while (!$b->is_zero())                                # found GCD if $b == 0
     {
-    ($a, my $q, $b) = ($b, $a->copy()->bdiv($b));
-    ($u, $u1) = ($u1, $u - $u1 * $q);
+    # the original algorithm had:
+    # ($u, $u1) = ($u1, $u->bsub($u1->copy()->bmul($q))); # step #2
+    # The following creates exact the same sequence of numbers in $u1,
+    # except for the sign ($u1 is now always positive). Since formerly
+    # the sign of $u1 was alternating between '-' and '+', the $sign
+    # flip-flop will take care of that, so that at the end of the loop
+    # we have the real sign of $u1. Keeping numbers positive gains us
+    # speed since badd() is faster than bsub() and makes it possible
+    # to have the algorithmn in Calc for even more speed.
+
+    ($u, $u1) = ($u1, $u->badd($u1->copy()->bmul($q))); # step #2
+    $sign = - $sign;                                    # flip sign
+
+    ($a, $q, $b) = ($b, $a->bdiv($b));                  # step #1 again
     }
 
-  # if the gcd is not 1, then return NaN!  It would be pointless to
-  # have called bgcd first, because we would then be performing the
-  # same Euclidean Algorithm *twice*
-  return $num->bnan() unless $a->is_one();
+  # If the gcd is not 1, then return NaN! It would be pointless to
+  # have called bgcd to check this first, because we would then be
+  # performing the same Euclidean Algorithm *twice*.
+  return $x->bnan() unless $a->is_one();
 
-  $u->bmod($mod);
-  $num->{value} = $u->{value};
-  $num->{sign} = $u->{sign};
-  $num;
+  $u1->bneg() if $sign != 1;                            # need to flip?
+
+  $u1->bmod($y);                                        # calc result
+  $x->{value} = $u1->{value};                           # and copy over to $x
+  $x->{sign} = $u1->{sign};                             # to modify in place
+  $x;
   }
 
 sub bmodpow
@@ -1474,40 +1582,38 @@ sub bmodpow
     return $num->bnan();
     }
 
- my $exp1 = $exp->copy();
- if ($exp->{sign} eq '-')
-    {
-    $exp1->babs();
-    $num->bmodinv ($mod);
-    # return $num if $num->{sign} !~ /^[+-]/;  # see next check
-    }
+  $num->bmodinv ($mod) if ($exp->{sign} eq '-');
 
-  # check num for valid values (also NaN if there was no inverse)
+  # check num for valid values (also NaN if there was no inverse but $exp < 0)
   return $num->bnan() if $num->{sign} !~ /^[+-]$/;
 
   if ($CALC->can('_modpow'))
     {
-    # $exp and $mod are positive, result is also positive
+    # $mod is positive, sign on $exp is ignored, result also positive
     $num->{value} = $CALC->_modpow($num->{value},$exp->{value},$mod->{value});
     return $num;
     }
 
   # in the trivial case,
-  return $num->bzero() if $mod->is_one();
-  return $num->bone() if $num->is_zero() or $num->is_one();
+  return $num->bzero(@r) if $mod->is_one();
+  return $num->bone('+',@r) if $num->is_zero() or $num->is_one();
 
-  $num->bmod($mod);            # if $x is large, make it smaller first
-  my $acc = $num->copy(); $num->bone();        # keep ref to $num
+  # $num->bmod($mod);           # if $x is large, make it smaller first
+  my $acc = $num->copy();      # but this is not really faster...
 
-  while( !$exp1->is_zero() )
+  $num->bone(); # keep ref to $num
+
+  my $expbin = $exp->as_bin(); $expbin =~ s/^[-]?0b//; # ignore sign and prefix
+  my $len = length($expbin);
+  while (--$len >= 0)
     {
-    if( $exp1->is_odd() )
+    if( substr($expbin,$len,1) eq '1')
       {
       $num->bmul($acc)->bmod($mod);
       }
     $acc->bmul($acc)->bmod($mod);
-    $exp1->brsft( 1, 2);               # remove last (binary) digit
     }
+
   $num;
   }
 
@@ -1518,12 +1624,12 @@ sub bfac
   # (BINT or num_str, BINT or num_str) return BINT
   # compute factorial numbers
   # modifies first argument
-  my ($self,$x,@r) = objectify(1,@_);
+  my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
 
   return $x if $x->modify('bfac');
  
   return $x->bnan() if $x->{sign} ne '+';      # inf, NnN, <0 etc => NaN
-  return $x->bone(@r) if $x->is_zero() || $x->is_one();                # 0 or 1 => 1
+  return $x->bone('+',@r) if $x->is_zero() || $x->is_one();    # 0 or 1 => 1
 
   if ($CALC->can('_fac'))
     {
@@ -1533,13 +1639,13 @@ sub bfac
 
   my $n = $x->copy();
   $x->bone();
+  # seems we need not to temp. clear A/P of $x since the result is the same
   my $f = $self->new(2);
   while ($f->bacmp($n) < 0)
     {
     $x->bmul($f); $f->binc();
     }
-  $x->bmul($f);                                        # last step
-  $x->round(@r);                               # round
+  $x->bmul($f,@r);                     # last step and also round
   }
  
 sub bpow 
@@ -1547,7 +1653,14 @@ sub bpow
   # (BINT or num_str, BINT or num_str) return BINT
   # compute power of two numbers -- stolen from Knuth Vol 2 pg 233
   # modifies first argument
-  my ($self,$x,$y,@r) = objectify(2,@_);
+  
+  # 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,@_);
+    }
 
   return $x if $x->modify('bpow');
 
@@ -1557,7 +1670,7 @@ sub bpow
   $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;
-  return $x->bone(@r) if $y->is_zero();
+  return $x->bone('+',@r) if $y->is_zero();
   return $x->round(@r) if $x->is_one() || $y->is_one();
   if ($x->{sign} eq '-' && $CALC->_is_one($x->{value}))
     {
@@ -1573,7 +1686,8 @@ sub bpow
   if ($CALC->can('_pow'))
     {
     $x->{value} = $CALC->_pow($x->{value},$y->{value});
-    return $x->round(@r);
+    $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+    return $x;
     }
 
 # based on the assumption that shifting in base 10 is fast, and that mul
@@ -1582,7 +1696,7 @@ sub bpow
 # stripping them out of the multiplication, and add $count * $y zeros
 # afterwards like this:
 # 300 ** 3 == 300*300*300 == 3*3*3 . '0' x 2 * 3 == 27 . '0' x 6
-# creates deep recursion?
+# creates deep recursion since brsft/blsft use bpow sometimes.
 #  my $zeros = $x->_trailing_zeros();
 #  if ($zeros > 0)
 #    {
@@ -1590,60 +1704,74 @@ sub bpow
 #    $x->bpow($y);             # recursion (will not branch into here again)
 #    $zeros = $y * $zeros;     # real number of zeros to add
 #    $x->blsft($zeros,10);
-#    return $x->round($a,$p,$r);
+#    return $x->round(@r);
 #    }
 
   my $pow2 = $self->__one();
-  my $y1 = $class->new($y);
-  my $two = $self->new(2);
-  while (!$y1->is_one())
+  my $y_bin = $y->as_bin(); $y_bin =~ s/^0b//;
+  my $len = length($y_bin);
+  while (--$len > 0)
     {
-    $pow2->bmul($x) if $y1->is_odd();
-    $y1->bdiv($two);
+    $pow2->bmul($x) if substr($y_bin,$len,1) eq '1';   # is odd?
     $x->bmul($x);
     }
-  $x->bmul($pow2) unless $pow2->is_one();
-  $x->round(@r);
+  $x->bmul($pow2);
+  $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0;
+  $x;
   }
 
 sub blsft 
   {
   # (BINT or num_str, BINT or num_str) return BINT
   # compute x << y, base n, y >= 0
-  my ($self,$x,$y,$n,$a,$p,$r) = objectify(2,@_);
-  
+  # set up parameters
+  my ($self,$x,$y,$n,@r) = (ref($_[0]),@_);
+  # objectify is costly, so avoid it
+  if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+    {
+    ($self,$x,$y,$n,@r) = objectify(2,@_);
+    }
+
   return $x if $x->modify('blsft');
   return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
-  return $x->round($a,$p,$r) if $y->is_zero();
+  return $x->round(@r) if $y->is_zero();
 
   $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 $CALC->can('_lsft');
   if (defined $t)
     {
-    $x->{value} = $t; return $x->round($a,$p,$r);
+    $x->{value} = $t; return $x->round(@r);
     }
   # fallback
-  return $x->bmul( $self->bpow($n, $y, $a, $p, $r), $a, $p, $r );
+  return $x->bmul( $self->bpow($n, $y, @r), @r );
   }
 
 sub brsft 
   {
   # (BINT or num_str, BINT or num_str) return BINT
   # compute x >> y, base n, y >= 0
-  my ($self,$x,$y,$n,$a,$p,$r) = objectify(2,@_);
+  
+  # set up parameters
+  my ($self,$x,$y,$n,@r) = (ref($_[0]),@_);
+  # objectify is costly, so avoid it
+  if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+    {
+    ($self,$x,$y,$n,@r) = objectify(2,@_);
+    }
 
   return $x if $x->modify('brsft');
   return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
-  return $x->round($a,$p,$r) if $y->is_zero();
-  return $x->bzero($a,$p,$r) if $x->is_zero();         # 0 => 0
+  return $x->round(@r) if $y->is_zero();
+  return $x->bzero(@r) if $x->is_zero();               # 0 => 0
 
   $n = 2 if !defined $n; return $x->bnan() if $n <= 0 || $y->{sign} eq '-';
 
    # this only works for negative numbers when shifting in base 2
   if (($x->{sign} eq '-') && ($n == 2))
     {
-    return $x->round($a,$p,$r) if $x->is_one('-');     # -1 => -1
+    return $x->round(@r) if $x->is_one('-');   # -1 => -1
     if (!$y->is_one())
       {
       # although this is O(N*N) in calc (as_bin!) it is O(N) in Pari et al
@@ -1671,7 +1799,7 @@ sub brsft
       my $res = $self->new('0b'.$bin); # add prefix and convert back
       $res->binc();                    # remember to increment
       $x->{value} = $res->{value};     # take over value
-      return $x->round($a,$p,$r);      # we are done now, magic, isn't?
+      return $x->round(@r);            # we are done now, magic, isn't?
       }
     $x->bdec();                                # n == 2, but $y == 1: this fixes it
     }
@@ -1680,10 +1808,10 @@ sub brsft
   if (defined $t)
     {
     $x->{value} = $t;
-    return $x->round($a,$p,$r);
+    return $x->round(@r);
     }
   # fallback
-  $x->bdiv($self->bpow($n,$y, $a,$p,$r), $a,$p,$r);
+  $x->bdiv($self->bpow($n,$y, @r), @r);
   $x;
   }
 
@@ -1691,14 +1819,22 @@ sub band
   {
   #(BINT or num_str, BINT or num_str) return BINT
   # compute x & y
-  my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
+  # 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,@_);
+    }
   
   return $x if $x->modify('band');
 
+  $r[3] = $y;                          # no push!
   local $Math::BigInt::upgrade = undef;
 
   return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
-  return $x->bzero() if $y->is_zero() || $x->is_zero();
+  return $x->bzero(@r) if $y->is_zero() || $x->is_zero();
 
   my $sign = 0;                                        # sign of result
   $sign = 1 if ($x->{sign} eq '-') && ($y->{sign} eq '-');
@@ -1708,7 +1844,7 @@ sub band
   if ($CALC->can('_and') && $sx == 1 && $sy == 1)
     {
     $x->{value} = $CALC->_and($x->{value},$y->{value});
-    return $x->round($a,$p,$r);
+    return $x->round(@r);
     }
 
   my $m = $self->bone(); my ($xr,$yr);
@@ -1728,21 +1864,29 @@ sub band
     $m->bmul($x10000);
     }
   $x->bneg() if $sign;
-  return $x->round($a,$p,$r);
+  $x->round(@r);
   }
 
 sub bior 
   {
   #(BINT or num_str, BINT or num_str) return BINT
   # compute x | y
-  my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
+  
+  # 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,@_);
+    }
 
   return $x if $x->modify('bior');
+  $r[3] = $y;                          # no push!
 
   local $Math::BigInt::upgrade = undef;
 
   return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
-  return $x if $y->is_zero();
+  return $x->round(@r) if $y->is_zero();
 
   my $sign = 0;                                        # sign of result
   $sign = 1 if ($x->{sign} eq '-') || ($y->{sign} eq '-');
@@ -1753,7 +1897,7 @@ sub bior
   if ($CALC->can('_or') && $sx == 1 && $sy == 1)
     {
     $x->{value} = $CALC->_or($x->{value},$y->{value});
-    return $x->round($a,$p,$r);
+    return $x->round(@r);
     }
 
   my $m = $self->bone(); my ($xr,$yr);
@@ -1773,21 +1917,29 @@ sub bior
     $m->bmul($x10000);
     }
   $x->bneg() if $sign;
-  return $x->round($a,$p,$r);
+  $x->round(@r);
   }
 
 sub bxor 
   {
   #(BINT or num_str, BINT or num_str) return BINT
   # compute x ^ y
-  my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
+  
+  # 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,@_);
+    }
 
   return $x if $x->modify('bxor');
+  $r[3] = $y;                          # no push!
 
   local $Math::BigInt::upgrade = undef;
 
   return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
-  return $x if $y->is_zero();
+  return $x->round(@r) if $y->is_zero();
   
   my $sign = 0;                                        # sign of result
   $sign = 1 if $x->{sign} ne $y->{sign};
@@ -1798,7 +1950,7 @@ sub bxor
   if ($CALC->can('_xor') && $sx == 1 && $sy == 1)
     {
     $x->{value} = $CALC->_xor($x->{value},$y->{value});
-    return $x->round($a,$p,$r);
+    return $x->round(@r);
     }
 
   my $m = $self->bone(); my ($xr,$yr);
@@ -1818,7 +1970,7 @@ sub bxor
     $m->bmul($x10000);
     }
   $x->bneg() if $sign;
-  return $x->round($a,$p,$r);
+  $x->round(@r);
   }
 
 sub length
@@ -1833,9 +1985,8 @@ sub digit
   {
   # return the nth decimal digit, negative values count backward, 0 is right
   my ($self,$x,$n) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
-  $n = 0 if !defined $n;
 
-  $CALC->_digit($x->{value},$n);
+  $CALC->_digit($x->{value},$n||0);
   }
 
 sub _trailing_zeros
@@ -1851,28 +2002,28 @@ sub _trailing_zeros
   # if not: since we do not know underlying internal representation:
   my $es = "$x"; $es =~ /([0]*)$/;
   return 0 if !defined $1;     # no zeros
-  return CORE::length("$1");   # as string, not as +0!
+  CORE::length("$1");          # as string, not as +0!
   }
 
 sub bsqrt
   {
-  my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_);
+  my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
 
   return $x if $x->modify('bsqrt');
 
   return $x->bnan() if $x->{sign} ne '+';      # -x or inf or NaN => NaN
-  return $x->bzero($a,$p) if $x->is_zero();                    # 0 => 0
-  return $x->round($a,$p,$r) if $x->is_one();                  # 1 => 1
+  return $x->bzero(@r) if $x->is_zero();                       # 0 => 0
+  return $x->round(@r) if $x->is_one();                        # 1 => 1
 
-  return $upgrade->bsqrt($x,$a,$p,$r) if defined $upgrade;
+  return $upgrade->bsqrt($x,@r) if defined $upgrade;
 
   if ($CALC->can('_sqrt'))
     {
     $x->{value} = $CALC->_sqrt($x->{value});
-    return $x->round($a,$p,$r);
+    return $x->round(@r);
     }
 
-  return $x->bone($a,$p) if $x < 4;                            # 2,3 => 1
+  return $x->bone('+',@r) if $x < 4;                           # 2,3 => 1
   my $y = $x->copy();
   my $l = int($x->length()/2);
   
@@ -1884,12 +2035,12 @@ sub bsqrt
   my $lastlast = $x+$two;
   while ($last != $x && $lastlast != $x)
     {
-    $lastlast = $last; $last = $x; 
-    $x += $y / $x; 
-    $x /= $two;
+    $lastlast = $last; $last = $x->copy(); 
+    $x->badd($y / $x); 
+    $x->bdiv($two);
     }
-  $x-- if $x * $x > $y;                                # overshot?
-  $x->round($a,$p,$r);
+  $x->bdec() if $x * $x > $y;                          # overshot?
+  $x->round(@r);
   }
 
 sub exponent
@@ -1921,7 +2072,6 @@ sub mantissa
   # that's inefficient
   my $zeros = $m->_trailing_zeros();
   $m->brsft($zeros,10) if $zeros != 0;
-#  $m /= 10 ** $zeros if $zeros != 0;
   $m;
   }
 
@@ -1972,7 +2122,8 @@ sub _scan_for_nonzero
   # since we do not know underlying represention of $x, use decimal string
   #my $r = substr ($$xs,-$follow);
   my $r = substr ("$x",-$follow);
-  return 1 if $r =~ /[^0]/; return 0;
+  return 1 if $r =~ /[^0]/;
+  0;
   }
 
 sub fround
@@ -2005,6 +2156,11 @@ sub bround
 
   # we have fewer digits than we want to scale to
   my $len = $x->length();
+  # convert $scale to a scalar in case it is an object (put's a limit on the
+  # number length, but this would already limited by memory constraints), makes
+  # it faster
+  $scale = $scale->numify() if ref ($scale);
+
   # scale < 0, but > -len (not >=!)
   if (($scale < 0 && $scale < -$len-1) || ($scale >= $len))
     {
@@ -2021,15 +2177,13 @@ sub bround
 
   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;
   $pl++; $pl ++ if $pad >= $len;
   $digit_after = '0'; $digit_after = substr($$xs,$pl,1) if $pad > 0;
 
- #  print "$pad $pl $$xs dr $digit_round da $digit_after\n";
-
   # 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
   my $round_up = 1;                                    # default round up
@@ -2048,25 +2202,6 @@ sub bround
     );
   my $put_back = 0;                                    # not yet modified
        
-  # old code, depend on internal representation
-  # split mantissa at $pad and then pad with zeros
-  #my $s5 = int($pad / 5);
-  #my $i = 0;
-  #while ($i < $s5)
-  #  {
-  #  $x->{value}->[$i++] = 0;                          # replace with 5 x 0
-  #  }
-  #$x->{value}->[$s5] = '00000'.$x->{value}->[$s5];    # pad with 0
-  #my $rem = $pad % 5;                         # so much left over
-  #if ($rem > 0)
-  #  {
-  #  #print "remainder $rem\n";
-  ##  #print "elem      $x->{value}->[$s5]\n";
-  #  substr($x->{value}->[$s5],-$rem,$rem) = '0' x $rem;       # stamp w/ '0'
-  #  }
-  #$x->{value}->[$s5] = int ($x->{value}->[$s5]);      # str '05' => int '5'
-  #print ${$CALC->_str($pad->{value})}," $len\n";
-
   if (($pad > 0) && ($pad <= $len))
     {
     substr($$xs,-$pad,$pad) = '0' x $pad;
@@ -2080,10 +2215,10 @@ 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  
+    $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
+    # adding it, since that is faster (we already have the string)
     my $c = 0; $pad ++;                                # for $pad == $len case
     while ($pad <= $len)
       {
@@ -2093,9 +2228,8 @@ sub bround
       }
     $$xs = '1'.$$xs if $c == 0;
 
-    # $x->badd( Math::BigInt->new($x->{sign}.'1'. '0' x $pad) );
     }
-  $x->{value} = $CALC->_new($xs) if $put_back == 1;    # put back in
+  $x->{value} = $CALC->_new($xs) if $put_back == 1;    # put back in if needed
 
   $x->{_a} = $scale if $scale >= 0;
   if ($scale < 0)
@@ -2110,20 +2244,18 @@ sub bfloor
   {
   # return integer less or equal then number, since it is already integer,
   # always returns $self
-  my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
+  my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
 
-  # not needed: return $x if $x->modify('bfloor');
-  return $x->round($a,$p,$r);
+  $x->round(@r);
   }
 
 sub bceil
   {
   # return integer greater or equal then number, since it is already integer,
   # always returns $self
-  my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
+  my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
 
-  # not needed: return $x if $x->modify('bceil');
-  return $x->round($a,$p,$r);
+  $x->round(@r);
   }
 
 ##############################################################################
@@ -2135,7 +2267,7 @@ sub __one
   my $self = shift;
   my $x = $self->bone(); # $x->{value} = $CALC->_one();
   $x->{sign} = shift || '+';
-  return $x;
+  $x;
   }
 
 sub _swap
@@ -2420,7 +2552,7 @@ sub _split
   $$x =~ s/\s+$//g;                    # strip white space at end
 
   # shortcut, if nothing to split, return early
-  if ($$x =~ /^[+-]?\d+$/)
+  if ($$x =~ /^[+-]?\d+\z/)
     {
     $$x =~ s/^([+-])0*([0-9])/$2/; my $sign = $1 || '+';
     return (\$sign, $x, \'', \'', \0);
@@ -2440,10 +2572,12 @@ sub _split
   # 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
 
-  return if $$x =~ /[Ee].*[Ee]/;       # more than one E => error
+  #return if $$x =~ /[Ee].*[Ee]/;      # more than one E => error
 
-  my ($m,$e) = 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 "";
+
   # sign,value for exponent,mantint,mantfrac
   my ($es,$ev,$mis,$miv,$mfv);
   # valid exponent?
@@ -2452,8 +2586,8 @@ sub _split
     $es = $1; $ev = $2;
     # valid mantissa?
     return if $m eq '.' || $m eq '';
-    my ($mi,$mf,$last) = split /\./,$m;
-    return if defined $last;           # last defined => 1.2.3 or others
+    my ($mi,$mf,$lastf) = split /\./,$m;
+    return if defined $lastf;          # last defined => 1.2.3 or others
     $mi = '0' if !defined $mi;
     $mi .= '0' if $mi =~ /^[\-\+]?$/;
     $mf = '0' if !defined $mf || $mf eq '';
@@ -2494,12 +2628,19 @@ sub as_hex
     }
   else
     {
-    my $x1 = $x->copy()->babs(); my $xr;
-    my $x10000 = Math::BigInt->new (0x10000);
+    my $x1 = $x->copy()->babs(); my ($xr,$x10000,$h);
+    if ($] >= 5.006)
+      {
+      $x10000 = Math::BigInt->new (0x10000); $h = 'h4';
+      }
+    else
+      {
+      $x10000 = Math::BigInt->new (0x1000); $h = 'h3';
+      }
     while (!$x1->is_zero())
       {
       ($x1, $xr) = bdiv($x1,$x10000);
-      $es .= unpack('h4',pack('v',$xr->numify()));
+      $es .= unpack($h,pack('v',$xr->numify()));
       }
     $es = reverse $es;
     $es =~ s/^[0]+//;  # strip leading zeros
@@ -2524,12 +2665,19 @@ sub as_bin
     }
   else
     {
-    my $x1 = $x->copy()->babs(); my $xr;
-    my $x10000 = Math::BigInt->new (0x10000);
+    my $x1 = $x->copy()->babs(); my ($xr,$x10000,$b);
+    if ($] >= 5.006)
+      {
+      $x10000 = Math::BigInt->new (0x10000); $b = 'b16';
+      }
+    else
+      {
+      $x10000 = Math::BigInt->new (0x1000); $b = 'b12';
+      }
     while (!$x1->is_zero())
       {
       ($x1, $xr) = bdiv($x1,$x10000);
-      $es .= unpack('b16',pack('v',$xr->numify()));
+      $es .= unpack($b,pack('v',$xr->numify()));
       }
     $es = reverse $es; 
     $es =~ s/^[0]+//;  # strip leading zeros
@@ -2595,95 +2743,109 @@ Math::BigInt - Arbitrary size integer math package
   $one = Math::BigInt->bone();         # create a +1
   $one = Math::BigInt->bone('-');      # create a -1
 
-  # Testing
-  $x->is_zero();               # true if arg is +0
-  $x->is_nan();                        # true if arg is NaN
-  $x->is_one();                        # true if arg is +1
-  $x->is_one('-');             # true if arg is -1
-  $x->is_odd();                        # true if odd, false for even
-  $x->is_even();               # true if even, false for odd
-  $x->is_positive();           # true if >= 0
-  $x->is_negative();           # true if <  0
-  $x->is_inf(sign);            # true if +inf, or -inf (sign is default '+')
-  $x->is_int();                        # true if $x is an integer (not a float)
-
-  $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
-  $x->digit($n);               # return the nth digit, counting from right
-  $x->digit(-$n);              # return the nth digit, counting from left
+  # Testing (don't modify their arguments)
+  # (return true if the condition is met, otherwise false)
+
+  $x->is_zero();       # if $x is +0
+  $x->is_nan();                # if $x is NaN
+  $x->is_one();                # if $x is +1
+  $x->is_one('-');     # if $x is -1
+  $x->is_odd();                # if $x is odd
+  $x->is_even();       # if $x is even
+  $x->is_positive();   # if $x >= 0
+  $x->is_negative();   # if $x <  0
+  $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
+  $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
+  $x->digit($n);       # return the nth digit, counting from right
+  $x->digit(-$n);      # return the nth digit, counting from left
 
   # The following all modify their first argument:
 
-  # set 
-  $x->bzero();                 # set $x to 0
-  $x->bnan();                  # set $x to NaN
-  $x->bone();                  # set $x to +1
-  $x->bone('-');               # set $x to -1
-  $x->binf();                  # set $x to inf
-  $x->binf('-');               # set $x to -inf
-
-  $x->bneg();                  # negation
-  $x->babs();                  # absolute value
-  $x->bnorm();                 # normalize (no-op)
-  $x->bnot();                  # two's complement (bit wise not)
-  $x->binc();                  # increment x by 1
-  $x->bdec();                  # decrement x by 1
+  $x->bzero();         # set $x to 0
+  $x->bnan();          # set $x to NaN
+  $x->bone();          # set $x to +1
+  $x->bone('-');       # set $x to -1
+  $x->binf();          # set $x to inf
+  $x->binf('-');       # set $x to -inf
+
+  $x->bneg();          # negation
+  $x->babs();          # absolute value
+  $x->bnorm();         # normalize (no-op in BigInt)
+  $x->bnot();          # two's complement (bit wise not)
+  $x->binc();          # increment $x by 1
+  $x->bdec();          # decrement $x by 1
   
-  $x->badd($y);                        # addition (add $y to $x)
-  $x->bsub($y);                        # subtraction (subtract $y from $x)
-  $x->bmul($y);                        # multiplication (multiply $x by $y)
-  $x->bdiv($y);                        # divide, set $x to quotient
-                               # return (quo,rem) or quo if scalar
-
-  $x->bmod($y);                        # modulus (x % y)
-  $x->bmodpow($exp,$mod);      # modular exponentation (($num**$exp) % $mod))
-  $x->bmodinv($mod);           # the inverse of $x in the given modulus $mod
-
-  $x->bpow($y);                        # power of arguments (x ** y)
-  $x->blsft($y);               # left shift
-  $x->brsft($y);               # right shift 
-  $x->blsft($y,$n);            # left shift, by base $n (like 10)
-  $x->brsft($y,$n);            # right shift, by base $n (like 10)
+  $x->badd($y);                # addition (add $y to $x)
+  $x->bsub($y);                # subtraction (subtract $y from $x)
+  $x->bmul($y);                # multiplication (multiply $x by $y)
+  $x->bdiv($y);                # divide, set $x to quotient
+                       # return (quo,rem) or quo if scalar
+
+  $x->bmod($y);                   # modulus (x % y)
+  $x->bmodpow($exp,$mod);  # modular exponentation (($num**$exp) % $mod))
+  $x->bmodinv($mod);      # the inverse of $x in the given modulus $mod
+
+  $x->bpow($y);                   # power of arguments (x ** y)
+  $x->blsft($y);          # left shift
+  $x->brsft($y);          # right shift 
+  $x->blsft($y,$n);       # left shift, by base $n (like 10)
+  $x->brsft($y,$n);       # right shift, by base $n (like 10)
   
-  $x->band($y);                        # bitwise and
-  $x->bior($y);                        # bitwise inclusive or
-  $x->bxor($y);                        # bitwise exclusive or
-  $x->bnot();                  # bitwise not (two's complement)
+  $x->band($y);                   # bitwise and
+  $x->bior($y);                   # bitwise inclusive or
+  $x->bxor($y);                   # bitwise exclusive or
+  $x->bnot();             # bitwise not (two's complement)
+
+  $x->bsqrt();            # calculate square-root
+  $x->bfac();             # factorial of $x (1*2*3*4*..$x)
 
-  $x->bsqrt();                 # calculate square-root
-  $x->bfac();                  # factorial of $x (1*2*3*4*..$x)
+  $x->round($A,$P,$mode);  # round to accuracy or precision using mode $r
+  $x->bround($N);          # accuracy: preserve $N digits
+  $x->bfround($N);         # round to $Nth digit, no-op for BigInts
 
-  $x->round($A,$P,$round_mode); # round to accuracy or precision using mode $r
-  $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,
+  # but do so in BigFloat:
 
-  # The following do not modify their arguments in BigInt, but do in BigFloat:
-  $x->bfloor();                        # return integer less or equal than $x
-  $x->bceil();                 # return integer greater or equal than $x
+  $x->bfloor();                   # return integer less or equal than $x
+  $x->bceil();            # return integer greater or equal than $x
   
   # The following do not modify their arguments:
 
-  bgcd(@values);               # greatest common divisor (no OO style)
-  blcm(@values);               # lowest common multiplicator (no OO style)
+  bgcd(@values);          # greatest common divisor (no OO style)
+  blcm(@values);          # lowest common multiplicator (no OO style)
  
-  $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
-
-  $x->exponent();              # return exponent as BigInt
-  $x->mantissa();              # return (signed) mantissa as BigInt
-  $x->parts();                 # return (mantissa,exponent) as BigInt
-  $x->copy();                  # make a true copy of $x (unlike $y = $x;)
-  $x->as_number();             # return as BigInt (in BigInt: same as copy())
+  $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
+
+  $x->exponent();         # return exponent as BigInt
+  $x->mantissa();         # return (signed) mantissa as BigInt
+  $x->parts();            # return (mantissa,exponent) as BigInt
+  $x->copy();             # make a true copy of $x (unlike $y = $x;)
+  $x->as_number();        # return as BigInt (in BigInt: same as copy())
   
-  # conversation to string 
-  $x->bstr();                  # normalized string
-  $x->bsstr();                 # normalized string in scientific notation
-  $x->as_hex();                        # as signed hexadecimal string with prefixed 0x
-  $x->as_bin();                        # as signed binary string with prefixed 0b
+  # conversation to string (do not modify their argument)
+  $x->bstr();             # normalized string
+  $x->bsstr();            # normalized string in scientific notation
+  $x->as_hex();                   # as signed hexadecimal string with prefixed 0x
+  $x->as_bin();                   # as signed binary string with prefixed 0b
   
-  Math::BigInt->config();      # return hash containing configuration/version
+
+  # precision and accuracy (see section about rounding for more)
+  $x->precision();        # return P of $x (or global, if P of $x undef)
+  $x->precision($n);      # set P of $x to $n
+  $x->accuracy();         # return A of $x (or global, if A of $x undef)
+  $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
 
 =head1 DESCRIPTION
 
@@ -2735,27 +2897,60 @@ return either undef, <0, 0 or >0 and are suited for sort.
 
 =head1 METHODS
 
-Each of the methods below accepts three additional parameters. These arguments
-$A, $P and $R are accuracy, precision and round_mode. Please see more in the
-section about ACCURACY and ROUNDIND.
+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
+L<ACCURACY and PRECISION> for more information.
 
 =head2 config
 
        use Data::Dumper;
 
        print Dumper ( Math::BigInt->config() );
+       print Math::BigInt->config()->{lib},"\n";
 
 Returns a hash containing the configuration, e.g. the version number, lib
-loaded etc.
+loaded etc. The following hash keys are currently filled in with the
+appropriate information.
+
+       key             Description
+                       Example
+       ============================================================
+       lib             Name of the Math library
+                       Math::BigInt::Calc
+       lib_version     Version of 'lib'
+                       0.30
+       class           The class of config you just called
+                       Math::BigInt
+       upgrade         To which class numbers are upgraded
+                       Math::BigFloat
+       downgrade       To which class numbers are downgraded
+                       undef
+       precision       Global precision
+                       undef
+       accuracy        Global accuracy
+                       undef
+       round_mode      Global round mode
+                       even
+       version         version number of the class you used
+                       1.61
+       div_scale       Fallback acccuracy for div
+                       40
+
+It is currently not supported to set the configuration parameters by passing
+a hash ref to C<config()>.
 
 =head2 accuracy
 
        $x->accuracy(5);                # local for $x
-       $class->accuracy(5);            # global for all members of $class
+       CLASS->accuracy(5);             # global for all members of CLASS
+       $A = $x->accuracy();            # read out
+       $A = CLASS->accuracy();         # read out
 
 Set or get the global or local accuracy, aka how many significant digits the
-results have. Please see the section about L<ACCURACY AND PRECISION> for
-further details.
+results have. 
+
+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:
 
@@ -2776,6 +2971,45 @@ represents the accuracy that will be in effect for $x:
        print $x->accuracy(),"\n";              # still 4
        print $y->accuracy(),"\n";              # 5, since global is 5
 
+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
+Math::BigInt and make the globals of the subclass aliases to the ones from
+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
+
+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.
+
+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:
+
+       $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:
+
+       $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
+
+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
+Math::BigInt and make the globals of the subclass aliases to the ones from
+Math::BigInt.
+
 =head2 brsft
 
        $x->brsft($y,$n);               
@@ -2925,44 +3159,44 @@ numbers.
 
 =head2 bnorm
 
-  $x->bnorm();                 # normalize (no-op)
+       $x->bnorm();                    # normalize (no-op)
 
 =head2 bnot
 
-  $x->bnot();                  # two's complement (bit wise not)
+       $x->bnot();                     # two's complement (bit wise not)
 
 =head2 binc
 
-  $x->binc();                  # increment x by 1
+       $x->binc();                     # increment x by 1
 
 =head2 bdec
 
-  $x->bdec();                  # decrement x by 1
+       $x->bdec();                     # decrement x by 1
 
 =head2 badd
 
-  $x->badd($y);                        # addition (add $y to $x)
+       $x->badd($y);                   # addition (add $y to $x)
 
 =head2 bsub
 
-  $x->bsub($y);                        # subtraction (subtract $y from $x)
+       $x->bsub($y);                   # subtraction (subtract $y from $x)
 
 =head2 bmul
 
-  $x->bmul($y);                        # multiplication (multiply $x by $y)
+       $x->bmul($y);                   # multiplication (multiply $x by $y)
 
 =head2 bdiv
 
-  $x->bdiv($y);                        # divide, set $x to quotient
-                               # return (quo,rem) or quo if scalar
+       $x->bdiv($y);                   # divide, set $x to quotient
+                                       # return (quo,rem) or quo if scalar
 
 =head2 bmod
 
-  $x->bmod($y);                        # modulus (x % y)
+       $x->bmod($y);                   # modulus (x % y)
 
 =head2 bmodinv
 
-  bmodinv($num,$mod);          # modular inverse (no OO style)
+       num->bmodinv($mod);             # modular inverse
 
 Returns the inverse of C<$num> in the given modulus C<$mod>.  'C<NaN>' is
 returned unless C<$num> is relatively prime to C<$mod>, i.e. unless
@@ -2970,74 +3204,78 @@ C<bgcd($num, $mod)==1>.
 
 =head2 bmodpow
 
-  bmodpow($num,$exp,$mod);     # modular exponentation ($num**$exp % $mod)
+       $num->bmodpow($exp,$mod);       # modular exponentation
+                                       # ($num**$exp % $mod)
 
 Returns the value of C<$num> taken to the power C<$exp> in the modulus
 C<$mod> using binary exponentation.  C<bmodpow> is far superior to
 writing
 
-  $num ** $exp % $mod
+       $num ** $exp % $mod
 
 because C<bmodpow> is much faster--it reduces internal variables into
 the modulus whenever possible, so it operates on smaller numbers.
 
 C<bmodpow> also supports negative exponents.
 
-  bmodpow($num, -1, $mod)
+       bmodpow($num, -1, $mod)
 
 is exactly equivalent to
 
-  bmodinv($num, $mod)
+       bmodinv($num, $mod)
 
 =head2 bpow
 
-  $x->bpow($y);                        # power of arguments (x ** y)
+       $x->bpow($y);                   # power of arguments (x ** y)
 
 =head2 blsft
 
-  $x->blsft($y);               # left shift
-  $x->blsft($y,$n);            # left shift, by base $n (like 10)
+       $x->blsft($y);          # left shift
+       $x->blsft($y,$n);       # left shift, in base $n (like 10)
 
 =head2 brsft
 
-  $x->brsft($y);               # right shift 
-  $x->brsft($y,$n);            # right shift, by base $n (like 10)
+       $x->brsft($y);          # right shift 
+       $x->brsft($y,$n);       # right shift, in base $n (like 10)
 
 =head2 band
 
-  $x->band($y);                        # bitwise and
+       $x->band($y);                   # bitwise and
 
 =head2 bior
 
-  $x->bior($y);                        # bitwise inclusive or
+       $x->bior($y);                   # bitwise inclusive or
 
 =head2 bxor
 
-  $x->bxor($y);                        # bitwise exclusive or
+       $x->bxor($y);                   # bitwise exclusive or
 
 =head2 bnot
 
-  $x->bnot();                  # bitwise not (two's complement)
+       $x->bnot();                     # bitwise not (two's complement)
 
 =head2 bsqrt
 
-  $x->bsqrt();                 # calculate square-root
+       $x->bsqrt();                    # calculate square-root
 
 =head2 bfac
 
-  $x->bfac();                  # factorial of $x (1*2*3*4*..$x)
+       $x->bfac();                     # factorial of $x (1*2*3*4*..$x)
 
 =head2 round
 
-  $x->round($A,$P,$round_mode); # round to accuracy or precision using mode $r
+       $x->round($A,$P,$round_mode);
+       
+Round $x to accuracy C<$A> or precision C<$P> using the round mode
+C<$round_mode>.
 
 =head2 bround
 
-  $x->bround($N);               # accuracy: preserve $N digits
+       $x->bround($N);               # accuracy: preserve $N digits
 
 =head2 bfround
 
-  $x->bfround($N);              # round to $Nth digit, no-op for BigInts
+       $x->bfround($N);              # round to $Nth digit, no-op for BigInts
 
 =head2 bfloor
 
@@ -3055,11 +3293,11 @@ does change $x in BigFloat.
 
 =head2 bgcd
 
-  bgcd(@values);               # greatest common divisor (no OO style)
+       bgcd(@values);          # greatest common divisor (no OO style)
 
 =head2 blcm
 
-  blcm(@values);               # lowest common multiplicator (no OO style)
+       blcm(@values);          # lowest common multiplicator (no OO style)
  
 head2 length
 
@@ -3084,31 +3322,31 @@ Return the signed mantissa of $x as BigInt.
 
 =head2 parts
 
-  $x->parts();                 # return (mantissa,exponent) as BigInt
+       $x->parts();            # return (mantissa,exponent) as BigInt
 
 =head2 copy
 
-  $x->copy();                  # make a true copy of $x (unlike $y = $x;)
+       $x->copy();             # make a true copy of $x (unlike $y = $x;)
 
 =head2 as_number
 
-  $x->as_number();             # return as BigInt (in BigInt: same as copy())
+       $x->as_number();        # return as BigInt (in BigInt: same as copy())
   
 =head2 bsrt
 
-  $x->bstr();                  # normalized string
+       $x->bstr();             # return normalized string
 
 =head2 bsstr
 
-  $x->bsstr();                 # normalized string in scientific notation
+       $x->bsstr();            # normalized string in scientific notation
 
 =head2 as_hex
 
-  $x->as_hex();                        # as signed hexadecimal string with prefixed 0x
+       $x->as_hex();           # as signed hexadecimal string with prefixed 0x
 
 =head2 as_bin
 
-  $x->as_bin();                        # as signed binary string with prefixed 0b
+       $x->as_bin();           # as signed binary string with prefixed 0b
 
 =head1 ACCURACY and PRECISION