Upgrade to Math::BigInt 1.54.
Jarkko Hietaniemi [Mon, 4 Mar 2002 01:18:02 +0000 (01:18 +0000)]
p4raw-id: //depot/perl@14972

12 files changed:
lib/Math/BigFloat.pm
lib/Math/BigInt.pm
lib/Math/BigInt/Calc.pm
lib/Math/BigInt/t/bare_mbf.t
lib/Math/BigInt/t/bare_mbi.t
lib/Math/BigInt/t/bigfltpm.t
lib/Math/BigInt/t/bigintpm.t
lib/Math/BigInt/t/config.t
lib/Math/BigInt/t/downgrade.t
lib/Math/BigInt/t/sub_mbf.t
lib/Math/BigInt/t/sub_mbi.t
lib/Math/BigInt/t/upgrade.t

index b7120cc..ad6588e 100644 (file)
@@ -155,8 +155,7 @@ sub new
       }
     return $downgrade->new("$$mis$$miv$$mfv"."E$$es$$ev");
     }
-
-  # print "mbf new $self->{sign} $self->{_m} e $self->{_e}\n";
+  # print "mbf new $self->{sign} $self->{_m} e $self->{_e} ",ref($self),"\n";
   $self->bnorm()->round(@r);           # first normalize, then round
   }
 
@@ -192,6 +191,13 @@ sub _bzero
   $self->{_e} = Math::BigInt->bone();
   }
 
+sub isa
+  {
+  my ($self,$class) = @_;
+  return if $class eq 'Math::BigInt';          # we aren't
+  return UNIVERSAL::isa($self,$class);
+  }
+
 ##############################################################################
 # string conversation
 
@@ -559,12 +565,19 @@ sub blog
 
   # http://www.efunda.com/math/taylor_series/logarithmic.cfm?search_string=log
 
-  # u = x-1, v = x +1
+  # u = x-1, v = x+1
   #              _                               _
-  # taylor:     |    u    1   u^3   1   u^5       |
+  # Taylor:     |    u    1   u^3   1   u^5       |
   # ln (x)  = 2 |   --- + - * --- + - * --- + ... |  x > 0
   #             |_   v    3   v^3   5   v^5      _|
 
+  # This takes much more steps to calculate the result: 
+  # u = x-1
+  #              _                               _
+  # Taylor:     |    u    1   u^2   1   u^3       |
+  # ln (x)  = 2 |   --- + - * --- + - * --- + ... |  x > 1/2
+  #             |_   x    2   x^2   3   x^3      _|
+
   # we need to limit the accuracy to protect against overflow
   my $fallback = 0;
   my $scale = 0;
@@ -598,34 +611,56 @@ sub blog
   # we also need to disable any set A or P on $x (_find_round_parameters took
   # them already into account), since these would interfere, too
   delete $x->{_a}; delete $x->{_p};
-  # need to disable $upgrade in BigInt, to aoid deep recursion
+  # need to disable $upgrade in BigInt, to avoid deep recursion
   local $Math::BigInt::upgrade = undef;
-  
-  my $v = $x->copy(); $v->binc();              # v = x+1
-  $x->bdec(); my $u = $x->copy();              # u = x-1; x = x-1
-
-  $x->bdiv($v,$scale);                                 # first term: u/v
-
-  my $below = $v->copy();
-  my $over = $u->copy();
-  $u *= $u; $v *= $v;                          # u^2, v^2
-  $below->bmul($v);                            # u^3, v^3
-  $over->bmul($u);
-  my $factor = $self->new(3); my $two = $self->new(2);
-
-  my $diff = $self->bone();
-  my $limit = $self->new("1E-". ($scale-1)); my $last;
-  # print "diff $diff limit $limit\n";
-  while ($diff->bcmp($limit) > 0)
-    {
-    #print "$x $over $below $factor\n";
-    $diff = $x->copy()->bsub($last)->babs();
-    #print "diff $diff $limit\n";
-    $last = $x->copy();
-    $x += $over->copy()->bdiv($below->copy()->bmul($factor),$scale);
-    $over *= $u; $below *= $v; $factor->badd($two);
-    }
-  $x->bmul($two);
+  my ($case,$limit,$v,$u,$below,$factor,$two,$next,$over,$f);
+
+  if (3 < 5)
+  #if ($x <= Math::BigFloat->new("0.5"))
+    {
+    $case = 0;
+  #  print "case $case $x < 0.5\n";
+    $v = $x->copy(); $v->binc();               # v = x+1
+    $x->bdec(); $u = $x->copy();               # u = x-1; x = x-1
+    $x->bdiv($v,$scale);                       # first term: u/v
+    $below = $v->copy();
+    $over = $u->copy();
+    $u *= $u; $v *= $v;                                # u^2, v^2
+    $below->bmul($v);                          # u^3, v^3
+    $over->bmul($u);
+    $factor = $self->new(3); $f = $self->new(2);
+    }
+  #else
+  #  {
+  #  $case = 1;
+  #  print "case 1 $x > 0.5\n";
+  #  $v = $x->copy();                          # v = x
+  #  $u = $x->copy(); $u->bdec();              # u = x-1;
+  #  $x->bdec(); $x->bdiv($v,$scale);          # first term: x-1/x
+  #  $below = $v->copy();
+  #  $over = $u->copy();
+  #  $below->bmul($v);                         # u^2, v^2
+  #  $over->bmul($u);
+  #  $factor = $self->new(2); $f = $self->bone();
+  #  }
+  $limit = $self->new("1E-". ($scale-1));
+  #my $steps = 0;
+  while (3 < 5)
+    {
+    # we calculate the next term, and add it to the last
+    # when the next term is below our limit, it won't affect the outcome
+    # anymore, so we stop
+    $next = $over->copy()->bdiv($below->copy()->bmul($factor),$scale);
+    last if $next->bcmp($limit) <= 0;
+    $x->badd($next);
+    # print "step $steps $x\n";
+    # calculate things for the next term
+    $over *= $u; $below *= $v; $factor->badd($f);
+    #$steps++;
+    }
+  $x->bmul(2) if $case == 0;
+  #print "took $steps steps\n";
   
   # shortcut to not run trough _find_round_parameters again
   if (defined $params[1])
@@ -758,7 +793,7 @@ sub bmul
 sub bdiv 
   {
   # (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return 
-  # (BFLOAT,BFLOAT) (quo,rem) or BINT (only rem)
+  # (BFLOAT,BFLOAT) (quo,rem) or BFLOAT (only rem)
   my ($self,$x,$y,$a,$p,$r) = objectify(2,@_);
 
   return $self->_div_inf($x,$y)
@@ -767,8 +802,8 @@ sub bdiv
   # x== 0 # also: or y == 1 or y == -1
   return wantarray ? ($x,$self->bzero()) : $x if $x->is_zero();
 
-  # upgrade 
-  return $upgrade->bdiv($x,$y,$a,$p,$r) if defined $upgrade;
+  # upgrade ?
+  return $upgrade->bdiv($upgrade->new($x),$y,$a,$p,$r) if defined $upgrade;
 
   # we need to limit the accuracy to protect against overflow
   my $fallback = 0;
@@ -811,6 +846,10 @@ sub bdiv
     # promote BigInts and it's subclasses (except when already a BigFloat)
     $y = $self->new($y) unless $y->isa('Math::BigFloat'); 
 
+    #print "bdiv $y ",ref($y),"\n";
+    # need to disable $upgrade in BigInt, to avoid deep recursion
+    local $Math::BigInt::upgrade = undef;      # should be parent class vs MBI
+
     # calculate the result to $scale digits and then round it
     # a * 10 ** b / c * 10 ** d => a/c * 10 ** (b-d)
     $x->{_m}->blsft($scale,10);
@@ -852,7 +891,7 @@ sub bdiv
       }
     return ($x,$rem);
     }
-  return $x;
+  $x;
   }
 
 sub bmod 
@@ -965,19 +1004,20 @@ sub bsqrt
     }
 
   # when user set globals, they would interfere with our calculation, so
-  # disable then and later re-enable them
+  # disable them and later re-enable them
   no strict 'refs';
   my $abr = "$self\::accuracy"; my $ab = $$abr; $$abr = undef;
   my $pbr = "$self\::precision"; my $pb = $$pbr; $$pbr = undef;
   # we also need to disable any set A or P on $x (_find_round_parameters took
   # them already into account), since these would interfere, too
   delete $x->{_a}; delete $x->{_p};
-  # need to disable $upgrade in BigInt, to aoid deep recursion
-  local $Math::BigInt::upgrade = undef;
+  # need to disable $upgrade in BigInt, to avoid deep recursion
+  local $Math::BigInt::upgrade = undef;        # should be really parent class vs MBI
 
   my $xas = $x->as_number();
   my $gs = $xas->copy()->bsqrt();      # some guess
 
+#  print "guess $gs\n";
   if (($x->{_e}->{sign} ne '-')                # guess can't be accurate if there are
                                        # digits after the dot
    && ($xas->bacmp($gs * $gs) == 0))   # guess hit the nail on the head?
@@ -998,6 +1038,7 @@ sub bsqrt
       # clear a/p after round, since user did not request it
       $x->{_a} = undef; $x->{_p} = undef;
       }
+    # re-enable A and P, upgrade is taken care of by "local"
     ${"$self\::accuracy"} = $ab; ${"$self\::precision"} = $pb;
     return $x;
     }
@@ -1006,7 +1047,6 @@ sub bsqrt
   my $lx = $x->{_m}->length();
   $scale = $lx if $scale < $lx;
   my $e = $self->new("1E-$scale");     # make test variable
-#  return $x->bnan() if $e->sign() eq 'NaN';
 
   my $y = $x->copy();
   my $two = $self->new(2);
@@ -1015,10 +1055,11 @@ sub bsqrt
   $y = $self->new($y) unless $y->isa('Math::BigFloat'); 
 
   my $rem;
-  while ($diff >= $e)
+  while ($diff->bacmp($e) >= 0)
     {
+    $rem = $y->copy()->bdiv($gs,$scale);
     $rem = $y->copy()->bdiv($gs,$scale)->badd($gs)->bdiv($two,$scale);
-    $diff = $rem->copy()->bsub($gs)->babs();
+    $diff = $rem->copy()->bsub($gs);
     $gs = $rem->copy();
     }
   # copy over to modify $x
@@ -1063,6 +1104,98 @@ sub bfac
   $x->bnorm()->round(@r);
   }
 
+sub _pow
+  {
+  # Calculate a power where $y is a non-integer, like 2 ** 0.5
+  my ($x,$y,$a,$p,$r) = @_;
+  my $self = ref($x);
+
+  # if $y == 0.5, it is sqrt($x)
+  return $x->bsqrt($a,$p,$r,$y) if $y->bcmp('0.5') == 0;
+
+  # u = y * ln x
+  #                _                             _
+  # Taylor:       |    u     u^2      u^3         |
+  # x ** y  = 1 + |   --- +  --- + * ----- + ...  |
+  #               |_   1     1*2     1*2*3       _|
+
+  # we need to limit the accuracy to protect against overflow
+  my $fallback = 0;
+  my $scale = 0;
+  my @params = $x->_find_round_parameters($a,$p,$r);
+
+  # no rounding at all, so must use fallback
+  if (scalar @params == 1)
+    {
+    # simulate old behaviour
+    $params[1] = $self->div_scale();   # and round to it as accuracy
+    $scale = $params[1]+4;             # at least four more for proper round
+    $params[3] = $r;                   # round mode by caller or undef
+    $fallback = 1;                     # to clear a/p afterwards
+    }
+  else
+    {
+    # the 4 below is empirical, and there might be cases where it is not
+    # enough...
+    $scale = abs($params[1] || $params[2]) + 4;        # take whatever is defined
+    }
+
+  # when user set globals, they would interfere with our calculation, so
+  # disable then and later re-enable them
+  no strict 'refs';
+  my $abr = "$self\::accuracy"; my $ab = $$abr; $$abr = undef;
+  my $pbr = "$self\::precision"; my $pb = $$pbr; $$pbr = undef;
+  # we also need to disable any set A or P on $x (_find_round_parameters took
+  # them already into account), since these would interfere, too
+  delete $x->{_a}; delete $x->{_p};
+  # need to disable $upgrade in BigInt, to avoid deep recursion
+  local $Math::BigInt::upgrade = undef;
+  my ($limit,$v,$u,$below,$factor,$next,$over);
+
+  $u = $x->copy()->blog($scale)->bmul($y);
+  $v = $self->bone();                          # 1
+  $factor = $self->new(2);                     # 2
+  $x->bone();                                  # first term: 1
+
+  $below = $v->copy();
+  $over = $u->copy();
+  $limit = $self->new("1E-". ($scale-1));
+  #my $steps = 0;
+  while (3 < 5)
+    {
+    # we calculate the next term, and add it to the last
+    # when the next term is below our limit, it won't affect the outcome
+    # anymore, so we stop
+    $next = $over->copy()->bdiv($below,$scale);
+    last if $next->bcmp($limit) <= 0;
+    $x->badd($next);
+#    print "at $x\n";
+    # calculate things for the next term
+    $over *= $u; $below *= $factor; $factor->binc();
+    #$steps++;
+    }
+  
+  # shortcut to not run trough _find_round_parameters again
+  if (defined $params[1])
+    {
+    $x->bround($params[1],$params[3]);         # then round accordingly
+    }
+  else
+    {
+    $x->bfround($params[2],$params[3]);                # then round accordingly
+    }
+  if ($fallback)
+    {
+    # clear a/p after round, since user did not request it
+    $x->{_a} = undef; $x->{_p} = undef;
+    }
+  # restore globals
+  $$abr = $ab; $$pbr = $pb;
+  $x;
+  }
+
 sub bpow 
   {
   # (BFLOAT or num_str, BFLOAT or num_str) return BFLOAT
@@ -1075,7 +1208,10 @@ sub bpow
   return $x->bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
   return $x->bone() if $y->is_zero();
   return $x         if $x->is_one() || $y->is_one();
-  my $y1 = $y->as_number();            # make bigint (trunc)
+
+  return $x->_pow($y,$a,$p,$r) if !$y->is_int();       # non-integer power
+
+  my $y1 = $y->as_number();            # make bigint
   # if ($x == -1)
   if ($x->{sign} eq '-' && $x->{_m}->is_one() && $x->{_e}->is_zero())
     {
index f6279a8..abe2c82 100644 (file)
@@ -18,7 +18,7 @@ package Math::BigInt;
 my $class = "Math::BigInt";
 require 5.005;
 
-$VERSION = '1.53';
+$VERSION = '1.54';
 use Exporter;
 @ISA =       qw( Exporter );
 @EXPORT_OK = qw( objectify _swap bgcd blcm); 
@@ -164,7 +164,8 @@ sub upgrade
   # make Class->upgrade() work
   my $self = shift;
   my $class = ref($self) || $self || __PACKAGE__;
-  if (defined $_[0])
+  # need to set new value?
+  if (@_ > 0)
     {
     my $u = shift;
     return ${"${class}::upgrade"} = $u;
@@ -178,7 +179,8 @@ sub downgrade
   # make Class->downgrade() work
   my $self = shift;
   my $class = ref($self) || $self || __PACKAGE__;
-  if (defined $_[0])
+  # need to set new value?
+  if (@_ > 0)
     {
     my $u = shift;
     return ${"${class}::downgrade"} = $u;
@@ -396,11 +398,35 @@ sub new
  
   # avoid numify-calls by not using || on $wanted!
   return $class->bzero($a,$p) if !defined $wanted;     # default to 0
-  return $class->copy($wanted,$a,$p,$r) if ref($wanted);
+  return $class->copy($wanted,$a,$p,$r)
+   if ref($wanted) && $wanted->isa($class);            # MBI or subclass
 
   $class->import() if $IMPORT == 0;            # make require work
   
-  my $self = {}; bless $self, $class;
+  my $self = bless {}, $class;
+
+  # shortcut for "normal" numbers
+  if ((!ref $wanted) && ($wanted =~ /^([+-]?)[1-9][0-9]*$/))
+    {
+    $self->{sign} = $1 || '+';
+    my $ref = \$wanted;
+    if ($wanted =~ /^[+-]/)
+     {
+      # remove sign without touching wanted
+      my $t = $wanted; $t =~ s/^[+-]//; $ref = \$t;
+      }
+    $self->{value} = $CALC->_new($ref);
+    no strict 'refs';
+    if ( (defined $a) || (defined $p) 
+        || (defined ${"${class}::precision"})
+        || (defined ${"${class}::accuracy"}) 
+       )
+      {
+      $self->round($a,$p,$r) unless (@_ == 4 && !defined $a && !defined $p);
+      }
+    return $self;
+    }
+
   # handle '+inf', '-inf' first
   if ($wanted =~ /^[+-]?inf$/)
     {
@@ -473,8 +499,7 @@ sub new
   # do not round for new($x,undef,undef) since that is used by MBF to signal
   # no rounding
   $self->round($a,$p,$r) unless @_ == 4 && !defined $a && !defined $p;
-  # print "mbi new $self\n";
-  return $self;
+  $self;
   }
 
 sub bnan
@@ -649,7 +674,7 @@ sub numify
   return $x->{sign} if $x->{sign} !~ /^[+-]$/;
   my $num = $CALC->_num($x->{value});
   return -$num if $x->{sign} eq '-';
-  return $num;
+  $num;
   }
 
 ##############################################################################
@@ -657,10 +682,10 @@ sub numify
 
 sub sign
   {
-  # return the sign of the number: +/-/NaN
+  # return the sign of the number: +/-/-inf/+inf/NaN
   my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); 
   
-  return $x->{sign};
+  $x->{sign};
   }
 
 sub _find_round_parameters
@@ -1102,6 +1127,7 @@ sub is_inf
   my ($self,$x,$sign) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
 
   $sign = '' if !defined $sign;
+  return 1 if $sign eq $x->{sign};             # match ("+inf" eq "+inf")
   return 0 if $sign !~ /^([+-]|)$/;
 
   if ($sign eq '')
@@ -1187,8 +1213,6 @@ sub bmul
   
   return $x if $x->modify('bmul');
 
-  $r[3] = $y;                          # no push here
   return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
 
   # inf handling
@@ -1202,6 +1226,11 @@ 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);
+  
+  $r[3] = $y;                          # no push here
 
   $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-'; # +1 * +1 or -1 * -1 => +
 
@@ -1266,6 +1295,9 @@ sub bdiv
   return $self->_div_inf($x,$y)
    if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero());
 
+  return $upgrade->bdiv($upgrade->new($x),$y,@r)
+   if defined $upgrade && $y->isa($upgrade);
+
   $r[3] = $y;                                  # no push!
 
   # 0 / something
@@ -1276,7 +1308,8 @@ sub bdiv
   my $cmp = $CALC->_acmp($x->{value},$y->{value});
   if (($cmp < 0) and (($x->{sign} eq $y->{sign}) or !wantarray))
     {
-    return $upgrade->bdiv($x,$y,@r) if defined $upgrade;
+    return $upgrade->bdiv($upgrade->new($x),$upgrade->new($y),@r)
+     if defined $upgrade;
 
     return $x->bzero()->round(@r) unless wantarray;
     my $t = $x->copy();      # make copy first, because $x->bzero() clobbers $x
@@ -1289,6 +1322,8 @@ sub bdiv
     return $x unless wantarray;
     return ($x->round(@r),$self->bzero(@r));
     }
+  return $upgrade->bdiv($upgrade->new($x),$upgrade->new($y),@r)
+   if defined $upgrade;
    
   # calc new sign and in case $y == +/- 1, return $x
   my $xsign = $x->{sign};                              # keep
@@ -1399,7 +1434,10 @@ sub bpow
   my ($self,$x,$y,@r) = objectify(2,@_);
 
   return $x if $x->modify('bpow');
+
+  return $upgrade->bpow($upgrade->new($x),$y,@r)
+   if defined $upgrade && $y->isa($upgrade);
+
   $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;
@@ -2038,13 +2076,10 @@ sub objectify
 
   # $x->unary_op();
   return (ref($_[1]),$_[1]) if (@_ == 2) && ($_[0]||0 == 1) && ref($_[1]);
-  # $x->binary_op($y);
-  #return (ref($_[1]),$_[1],$_[2]) if (@_ == 3) && ($_[0]||0 == 2)
-  # && ref($_[1]) && ref($_[2]);
 
   my $count = abs(shift || 0);
   
-  my @a;                       # resulting array 
+  my (@a,$k,$d);               # resulting array, temp, and downgrade 
   if (ref $_[0])
     {
     # okay, got object as first
@@ -2056,8 +2091,15 @@ sub objectify
     $a[0] = $class;
     $a[0] = shift if $_[0] =~ /^[A-Z].*::/;    # classname as first?
     }
+  no strict 'refs';
+  # disable downgrading, because Math::BigFLoat->foo('1.0','2.0') needs floats
+  if (defined ${"$a[0]::downgrade"})
+    {
+    $d = ${"$a[0]::downgrade"};
+    ${"$a[0]::downgrade"} = undef;
+    }
+
   # print "Now in objectify, my class is today $a[0]\n";
-  my $k; 
   if ($count == 0)
     {
     while (@_)
@@ -2095,6 +2137,7 @@ sub objectify
     push @a,@_;                # return other params, too
     }
   die "$class objectify needs list context" unless wantarray;
+  ${"$a[0]::downgrade"} = $d;
   @a;
   }
 
index fae8cae..de4f46e 100644 (file)
@@ -8,7 +8,7 @@ require Exporter;
 use vars qw/@ISA $VERSION/;
 @ISA = qw(Exporter);
 
-$VERSION = '0.24';
+$VERSION = '0.25';
 
 # Package to store unsigned big integers in decimal and do math with them
 
@@ -234,8 +234,8 @@ sub _to_small
 sub _new
   {
   # (ref to string) return ref to num_array
-  # Convert a number from string format to internal base 100000 format.
-  # Assumes normalized value as input.
+  # Convert a number from string format (without sign) to internal base
+  # 1ex format. Assumes normalized value as input.
   my $d = $_[1];
   my $il = length($$d)-1;
   # this leaves '00000' instead of int 0 and will be corrected after any op
@@ -390,7 +390,7 @@ sub _dec
 
 sub _sub
   {
-  # (ref to int_num_array, ref to int_num_array)
+  # (ref to int_num_array, ref to int_num_array, swap)
   # subtract base 1eX numbers -- stolen from Knuth Vol 2 pg 232, $x > $y
   # subtract Y from X (X is always greater/equal!) by modifying x in place
   my ($c,$sx,$sy,$s) = @_;
@@ -419,9 +419,46 @@ sub _sub
   __strip_zeros($sy);
   }                                                                             
 
+sub _square_use_mul
+  {
+  # compute $x ** 2 or $x * $x in-place and return $x
+  my ($c,$x) = @_;
+
+  # From: Handbook of Applied Cryptography by A. Menezes, P. van Oorschot and
+  #       S. Vanstone., Chapter 14
+
+  #14.16 Algorithm Multiple-precision squaring
+  #INPUT: positive integer x = (xt 1 xt 2 ... x1 x0)b.
+  #OUTPUT: x * x = x ** 2 in radix b representation. 
+  #1. For i from 0 to (2t - 1) do: wi <- 0. 
+  #2.  For i from 0 to (t - 1) do the following: 
+  # 2.1 (uv)b w2i + xi * xi, w2i v, c u. 
+  # 2.2 For j from (i + 1)to (t - 1) do the following: 
+  #      (uv)b <- wi+j + 2*xj * xi + c, wi+j <- v, c <- u. 
+  # 2.3 wi+t <- u. 
+  #3. Return((w2t-1 w2t-2 ... w1 w0)b).
+
+#  # Note: That description is crap. Half of the symbols are not explained or
+#  # used with out beeing set.
+#  my $t = scalar @$x;         # count
+#  my ($c,$i,$j);
+#  for ($i = 0; $i < $t; $i++)
+#    {
+#    $x->[$i] = $x->[$i*2] + $x[$i]*$x[$i];
+#    $x->[$i*2] = $x[$i]; $c = $x[$i];
+#    for ($j = $i+1; $j < $t; $j++)
+#      {
+#      $x->[$i] = $x->[$i+$j] + 2 * $x->[$i] * $x->[$j];
+#      $x->[$i+$j] = $x[$j]; $c = $x[$i];
+#      }
+#    $x->[$i+$t] = $x[$i];
+#    }
+  $x;
+  }
+
 sub _mul_use_mul
   {
-  # (BINT, BINT) return nothing
+  # (ref to int_num_array, ref to int_num_array)
   # multiply two numbers in internal representation
   # modifies first arg, second need not be different from first
   my ($c,$xv,$yv) = @_;
@@ -446,6 +483,9 @@ sub _mul_use_mul
 
   # since multiplying $x with $x fails, make copy in this case
   $yv = [@$xv] if "$xv" eq "$yv";      # same references?
+  # since multiplying $x with $x would fail here, use the faster squaring
+#  return _square($c,$xv) if "$xv" eq "$yv";   # same reference?
+
   if ($LEN_CONVERT != 0)
     {
     $c->_to_small($xv); $c->_to_small($yv);
@@ -496,7 +536,7 @@ sub _mul_use_mul
 
 sub _mul_use_div
   {
-  # (BINT, BINT) return nothing
+  # (ref to int_num_array, ref to int_num_array)
   # multiply two numbers in internal representation
   # modifies first arg, second need not be different from first
   my ($c,$xv,$yv) = @_;
@@ -523,6 +563,9 @@ sub _mul_use_div
  
   # since multiplying $x with $x fails, make copy in this case
   $yv = [@$xv] if "$xv" eq "$yv";      # same references?
+  # since multiplying $x with $x would fail here, use the faster squaring
+#  return _square($c,$xv) if "$xv" eq "$yv";   # same reference?
+
   if ($LEN_CONVERT != 0)
     {
     $c->_to_small($xv); $c->_to_small($yv);
@@ -865,9 +908,14 @@ sub _acmp
   # manual way (abort if unequal, good for early ne)
   my $j = scalar @$cx - 1;
   while ($j >= 0)
-   {
-   last if ($a = $cx->[$j] - $cy->[$j]); $j--;
-   }
+    {
+    last if ($a = $cx->[$j] - $cy->[$j]); $j--;
+    }
+#  my $j = scalar @$cx;
+#  while (--$j >= 0)
+#    {
+#    last if ($a = $cx->[$j] - $cy->[$j]);
+#    }
   return 1 if $a > 0;
   return -1 if $a < 0;
   0;                                   # equal
index 78668c3..8288d2b 100644 (file)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 1586;
+  plan tests => 1592;
   }
 
 use Math::BigInt lib => 'BareCalc';
index 3d8d086..d480062 100644 (file)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 2143;
+  plan tests => 2147;
   }
 
 use Math::BigInt lib => 'BareCalc';
@@ -37,7 +37,7 @@ use vars qw ($class $try $x $y $f @args $ans $ans1 $ans1_str $setup $CL);
 $class = "Math::BigInt";
 $CL = "Math::BigInt::BareCalc";
 
-my $version = '1.51';   # for $VERSION tests, match current release (by hand!)
+my $version = '1.54';   # for $VERSION tests, match current release (by hand!)
 
 require 'bigintpm.inc';        # perform same tests as bigintpm
 
index 28ae2b3..2b4f83a 100755 (executable)
@@ -26,7 +26,7 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 1586;
+  plan tests => 1592;
   }
 
 use Math::BigInt;
index c62b943..eca2d29 100755 (executable)
@@ -10,7 +10,7 @@ BEGIN
   my $location = $0; $location =~ s/bigintpm.t//;
   unshift @INC, $location; # to locate the testing files
   chdir 't' if -d 't';
-  plan tests => 2143;
+  plan tests => 2147;
   }
 
 use Math::BigInt;
index c3a222b..fc3e52f 100644 (file)
@@ -22,7 +22,7 @@ my $cfg = Math::BigInt->config();
 ok (ref($cfg),'HASH');
 
 ok ($cfg->{lib},'Math::BigInt::Calc');
-ok ($cfg->{lib_version},'0.24');
+ok ($cfg->{lib_version},'0.25');
 ok ($cfg->{class},'Math::BigInt');
 ok ($cfg->{upgrade}||'','');
 ok ($cfg->{div_scale},40);
index 1309894..0208a56 100644 (file)
@@ -7,13 +7,13 @@ BEGIN
   {
   $| = 1;
   unshift @INC, '../lib'; # for running manually
-  my $location = $0; $location =~ s/bigintpm.t//;
+  my $location = $0; $location =~ s/downgrade.t//;
   unshift @INC, $location; # to locate the testing files
   chdir 't' if -d 't';
-  plan tests => 10;
+  plan tests => 12;
   }
 
-use Math::BigInt;
+use Math::BigInt upgrade => 'Math::BigFloat';
 use Math::BigFloat downgrade => 'Math::BigInt', upgrade => 'Math::BigInt';
 
 use vars qw ($scale $class $try $x $y $f @args $ans $ans1 $ans1_str $setup
@@ -36,4 +36,14 @@ ok (ref(Math::BigFloat->new('10')),'Math::BigInt');
 ok (ref(Math::BigFloat->new('-10')),'Math::BigInt');
 ok (ref(Math::BigFloat->new('-10.0E1')),'Math::BigInt');
 
+# disable, otherwise it screws calculations
+Math::BigFloat->upgrade(undef);
+ok (Math::BigFloat->upgrade()||'','');
+
+Math::BigFloat->div_scale(20);                                 # make it a bit faster
+my $x = Math::BigFloat->new(2);                                # downgrades
+# the following test upgrade for bsqrt() and also makes new() NOT downgrade
+# for the bpow() side
+ok (Math::BigFloat->bpow('2','0.5'),$x->bsqrt());
+
 #require 'upgrade.inc';        # all tests here for sharing
index 2035035..3df9ce4 100755 (executable)
@@ -26,8 +26,8 @@ BEGIN
     }
   print "# INC = @INC\n"; 
   
-  plan tests => 1586
-    + 4;       # + 4 own tests
+  plan tests => 1592
+    + 6;       # + our own tests
   }
 
 use Math::BigFloat::Subclass;
@@ -38,10 +38,15 @@ $CL = "Math::BigInt::Calc";
 
 require 'bigfltpm.inc';        # perform same tests as bigfltpm
 
+###############################################################################
 # Now do custom tests for Subclass itself
 my $ms = $class->new(23);
 print "# Missing custom attribute \$ms->{_custom}" if !ok (1, $ms->{_custom});
 
+# Check that subclass is a Math::BigFloat, but not a Math::Bigint
+ok ($ms->isa('Math::BigFloat'),1);
+ok ($ms->isa('Math::BigInt') || 0,0);
+
 use Math::BigFloat;
 
 my $bf = Math::BigFloat->new(23);              # same as other
index d0a235a..c492592 100755 (executable)
@@ -26,8 +26,8 @@ BEGIN
     }
   print "# INC = @INC\n";
 
-  plan tests => 2143
-    + 4;       # +4 own tests
+  plan tests => 2147
+    + 5;       # +4 own tests
   }
 
 use Math::BigInt::Subclass;
@@ -40,10 +40,15 @@ my $version = '0.02';   # for $VERSION tests, match current release (by hand!)
 
 require 'bigintpm.inc';        # perform same tests as bigintpm
 
+###############################################################################
 # Now do custom tests for Subclass itself
 my $ms = $class->new(23);
 print "# Missing custom attribute \$ms->{_custom}" if !ok (1, $ms->{_custom});
 
+# Check that a subclass is still considered a BigInt
+ok ($ms->isa('Math::BigInt'),1);
+
 use Math::BigInt;
 
 my $bi = Math::BigInt->new(23);                # same as other
index 86bd139..17d505c 100644 (file)
@@ -6,27 +6,12 @@ use strict;
 BEGIN
   {
   $| = 1;
-  # to locate the testing files
-  my $location = $0; $location =~ s/upgrade.t//i;
-  if ($ENV{PERL_CORE})
-    {
-    @INC = qw(../t/lib);                # testing with the core distribution
-    }
-  unshift @INC, '../lib';       # for testing manually
-  if (-d 't')
-    {
-    chdir 't';
-    require File::Spec;
-    unshift @INC, File::Spec->catdir(File::Spec->updir, $location);
-    }
-  else
-    {
-    unshift @INC, $location;
-    }
-  print "# INC = @INC\n";
-
-   plan tests => 1990
-    + 2;                       # our own tests
+  unshift @INC, '../lib'; # for running manually
+  my $location = $0; $location =~ s/bigintpm.t//;
+  unshift @INC, $location; # to locate the testing files
+  chdir 't' if -d 't';
+  plan tests => 2056
+   + 2;                        # our own tests
   }
 
 use Math::BigInt upgrade => 'Math::BigFloat';