Change 33666 by [EMAIL PROTECTED] on 2008/04/11 10:53:40

        Subject: [PATCH] Math::BigRat 0.22
        From: Tels <[EMAIL PROTECTED]>
        Date: Mon, 7 Apr 2008 21:27:30 +0200
        Message-Id: <[EMAIL PROTECTED]>

Affected files ...

... //depot/perl/MANIFEST#1692 edit
... //depot/perl/lib/Math/BigRat.pm#21 edit
... //depot/perl/lib/Math/BigRat/t/biglog.t#2 edit
... //depot/perl/lib/Math/BigRat/t/bigrat.t#13 edit
... //depot/perl/lib/Math/BigRat/t/bigroot.t#2 edit
... //depot/perl/lib/Math/BigRat/t/hang.t#1 add

Differences ...

==== //depot/perl/MANIFEST#1692 (text) ====
Index: perl/MANIFEST
--- perl/MANIFEST#1691~33643~   2008-04-03 10:14:51.000000000 -0700
+++ perl/MANIFEST       2008-04-11 03:53:40.000000000 -0700
@@ -2127,6 +2127,7 @@
 lib/Math/BigRat/t/bigrat.t             Math::BigRat test
 lib/Math/BigRat/t/bigratup.t   test under $Math::BigInt::upgrade
 lib/Math/BigRat/t/bigroot.t            Math::BigRat test
+lib/Math/BigRat/t/hang.t               Math::BigRat test for bug #34584 - hang 
in exp()
 lib/Math/BigRat/t/requirer.t   see if require works properly
 lib/Math/BigRat/t/trap.t       see if trap_nan and trap_inf work
 lib/Math/Complex.pm            A Complex package

==== //depot/perl/lib/Math/BigRat.pm#21 (text) ====
Index: perl/lib/Math/BigRat.pm
--- perl/lib/Math/BigRat.pm#20~31875~   2007-09-16 03:48:40.000000000 -0700
+++ perl/lib/Math/BigRat.pm     2008-04-11 03:53:40.000000000 -0700
@@ -23,7 +23,7 @@
 
 @ISA = qw(Math::BigFloat);
 
-$VERSION = '0.21';
+$VERSION = '0.22';
 
 use overload;                  # inherit overload from Math::BigFloat
 
@@ -937,6 +937,13 @@
 
   return $x->round(@r) if $x->is_zero();  # 0**y => 0 (if not y <= 0)
 
+  # shortcut if y == 1/N (is then sqrt() respective broot())
+  if ($MBI->_is_one($y->{_n}))
+    {
+    return $x->bsqrt(@r) if $MBI->_is_two($y->{_d});   # 1/2 => sqrt
+    return $x->broot($MBI->_str($y->{_d}),@r);         # 1/N => root(N)
+    }
+
   # shortcut y/1 (and/or x/1)
   if ($MBI->_is_one($y->{_d}))
     {
@@ -974,21 +981,18 @@
     return $x->round(@r);
     }
 
-  # regular calculation (this is wrong for d/e ** f/g)
-  my $pow2 = $self->bone();
-  my $y1 = $MBI->_div ( $MBI->_copy($y->{_n}), $y->{_d});
-  my $two = $MBI->_two();
-
-  while (!$MBI->_is_one($y1))
-    {
-    $pow2->bmul($x) if $MBI->_is_odd($y1);
-    $MBI->_div($y1, $two);
-    $x->bmul($x);
-    }
-  $x->bmul($pow2) unless $pow2->is_one();
-  # n ** -x => 1/n ** x
-  ($x->{_d},$x->{_n}) = ($x->{_n},$x->{_d}) if $y->{sign} eq '-'; 
-  $x->bnorm()->round(@r);
+#  print STDERR "# $x $y\n";
+
+  # otherwise:
+
+  #      n/d     n  ______________
+  # a/b       =  -\/  (a/b) ** d
+
+  # (a/b) ** n == (a ** n) / (b ** n)
+  $MBI->_pow($x->{_n}, $y->{_n} );
+  $MBI->_pow($x->{_d}, $y->{_n} );
+
+  return $x->broot($MBI->_str($y->{_d}),@r);           # n/d => root(n)
   }
 
 sub blog
@@ -1020,21 +1024,21 @@
 sub bexp
   {
   # set up parameters
-  my ($self,$x,$y,$a,$p,$r) = (ref($_[0]),@_);
+  my ($self,$x,$y,@r) = (ref($_[0]),@_);
 
   # objectify is costly, so avoid it
   if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
     {
-    ($self,$x,$y,$a,$p,$r) = objectify(2,$class,@_);
+    ($self,$x,$y,@r) = objectify(2,$class,@_);
     }
 
-  return $x->binf() if $x->{sign} eq '+inf';
-  return $x->bzero() if $x->{sign} eq '-inf';
+  return $x->binf(@r) if $x->{sign} eq '+inf';
+  return $x->bzero(@r) if $x->{sign} eq '-inf';
 
   # we need to limit the accuracy to protect against overflow
   my $fallback = 0;
   my ($scale,@params);
-  ($x,@params) = $x->_find_round_parameters($a,$p,$r);
+  ($x,@params) = $x->_find_round_parameters(@r);
 
   # also takes care of the "error in _find_round_parameters?" case
   return $x if $x->{sign} eq 'NaN';
@@ -1043,11 +1047,11 @@
   if (scalar @params == 0)
     {
     # simulate old behaviour
-    $params[0] = $self->div_scale();    # and round to it as accuracy
-    $params[1] = undef;                 # P = undef
-    $scale = $params[0]+4;              # at least four more for proper round
-    $params[2] = $r;                    # round mode by caller or undef
-    $fallback = 1;                      # to clear a/p afterwards
+    $params[0] = $self->div_scale();   # and round to it as accuracy
+    $params[1] = undef;                        # P = undef
+    $scale = $params[0]+4;             # at least four more for proper round
+    $params[2] = $r[2];                        # round mode by caller or undef
+    $fallback = 1;                     # to clear a/p afterwards
     }
   else
     {
@@ -1165,7 +1169,7 @@
   if ($a != 0 || !$MBI->_is_one($x->{_d}))
     {
     # n/d
-    return Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}))->bdiv( 
$MBI->_str($x->{_d}), $x->accuracy());
+    return scalar Math::BigFloat->new($x->{sign} . 
$MBI->_str($x->{_n}))->bdiv( $MBI->_str($x->{_d}), $x->accuracy());
     }
   # just n
   Math::BigFloat->new($x->{sign} . $MBI->_str($x->{_n}));
@@ -1187,7 +1191,7 @@
     }
 
   # do it with floats
-  $x->_new_from_float( $x->_as_float()->broot($y,@r) );
+  $x->_new_from_float( $x->_as_float()->broot($y->_as_float(),@r) 
)->bnorm()->bround(@r);
   }
 
 sub bmodpow
@@ -1418,6 +1422,28 @@
   $u;
   }
 
+sub as_float
+  {
+  # return N/D as Math::BigFloat
+
+  # set up parameters
+  my ($self,$x,@r) = (ref($_[0]),@_);
+  # objectify is costly, so avoid it
+  ($self,$x,@r) = objectify(1,$class,@_) unless ref $_[0];
+
+  # NaN, inf etc
+  return Math::BigFloat->new($x->{sign}) if $x->{sign} !~ /^[+-]$/;
+ 
+  my $u = Math::BigFloat->bzero();
+  $u->{sign} = $x->{sign};
+  # n
+  $u->{_m} = $MBI->_copy($x->{_n});
+  $u->{_e} = $MBI->_zero();
+  $u->bdiv( $MBI->_str($x->{_d}), @r);
+  # return $u
+  $u;
+  }
+
 sub as_bin
   {
   my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
@@ -1655,7 +1681,7 @@
 
 Returns the object as a scalar. This will lose some data if the object
 cannot be represented by a normal Perl scalar (integer or float), so
-use as_int() instead.
+use L<as_int()> or L<as_float()> instead.
 
 This routine is automatically used whenever a scalar is required:
 
@@ -1672,6 +1698,19 @@
 
 C<as_number()> is an alias for C<as_int()>.
 
+=head2 as_float()
+
+       $x = Math::BigRat->new('13/7');
+       print $x->as_float(),"\n";              # '1'
+
+       $x = Math::BigRat->new('2/3');
+       print $x->as_float(5),"\n";             # '0.66667'
+
+Returns a copy of the object as BigFloat, preserving the
+accuracy as wanted, or the default of 40 digits.
+
+This method was added in v0.22 of Math::BigRat (April 2008).
+
 =head2 as_hex()
 
        $x = Math::BigRat->new('13');
@@ -1933,6 +1972,10 @@
 works only for values that a marked with a C<RW> above, anything else is
 read-only.
 
+=head2 objectify()
+
+This is an internal routine that turns scalars into objects.
+
 =head1 BUGS
 
 Some things are not yet implemented, or only implemented half-way:
@@ -1969,6 +2012,6 @@
 
 =head1 AUTHORS
 
-(C) by Tels L<http://bloodgate.com/> 2001 - 2007.
+(C) by Tels L<http://bloodgate.com/> 2001 - 2008.
 
 =cut

==== //depot/perl/lib/Math/BigRat/t/biglog.t#2 (text) ====
Index: perl/lib/Math/BigRat/t/biglog.t
--- perl/lib/Math/BigRat/t/biglog.t#1~31629~    2007-07-18 11:52:12.000000000 
-0700
+++ perl/lib/Math/BigRat/t/biglog.t     2008-04-11 03:53:40.000000000 -0700
@@ -28,7 +28,7 @@
     }
   print "# INC = @INC\n";
 
-  plan tests => 14;
+  plan tests => 17;
   }
 
 use Math::BigRat;
@@ -66,18 +66,18 @@
   '90933395208605785401971970164779391644753259799242' . '/' .
   '33452526613163807108170062053440751665152000000000',
   'bexp(1)');
-#is ($cl->new(2)->bexp(40), $cl->new(1)->bexp(45)->bpow(2,40), 'bexp(2)'); 
+is ($cl->new(2)->bexp(1,40), $cl->new(1)->bexp(1,45)->bpow(2,40), 'bexp(2)'); 
 
-#is ($cl->new("12.5")->bexp(61), $cl->new(1)->bexp(65)->bpow(12.5,61), 
'bexp(12.5)'); 
+is ($cl->new("12.5")->bexp(1,61), $cl->new(1)->bexp(1,65)->bpow(12.5,61), 
'bexp(12.5)'); 
 
 #############################################################################
 # test bexp() with big values (non-cached)
 
-#is ($cl->new(1)->bexp(100), 
-#  
'2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427',
-# 'bexp(100)');
+is ($cl->new(1)->bexp(1,100)->as_float(100), 
+  
'2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427',
+ 'bexp(100)');
 
-is ($cl->new("12.5")->bexp(91), $cl->new(1)->bexp(95)->bpow(12.5,91), 
+is ($cl->new("12.5")->bexp(1,91), $cl->new(1)->bexp(1,95)->bpow(12.5,91), 
   'bexp(12.5) to 91 digits'); 
 
 #############################################################################

==== //depot/perl/lib/Math/BigRat/t/bigrat.t#13 (xtext) ====
Index: perl/lib/Math/BigRat/t/bigrat.t
--- perl/lib/Math/BigRat/t/bigrat.t#12~30359~   2007-02-19 11:23:03.000000000 
-0800
+++ perl/lib/Math/BigRat/t/bigrat.t     2008-04-11 03:53:40.000000000 -0700
@@ -8,7 +8,7 @@
   $| = 1;
   chdir 't' if -d 't';
   unshift @INC, '../lib'; # for running manually
-  plan tests => 193;
+  plan tests => 198;
   }
 
 # basic testing of Math::BigRat
@@ -197,8 +197,8 @@
 $x = $cr->new('1/3');  $z = $x->bpow('4/1'); ok ($x,'1/81');
 $x = $cr->new('2/3');  $z = $x->bpow('4/1'); ok ($x,'16/81');
 
-# XXX todo:
-#$x = $cr->new('2/3');  $z = $x->bpow('5/3'); ok ($x,'32/81 ???');
+$x = $cr->new('2/3');  $z = $x->bpow('5/3'); 
+ok ($x, 
'31797617848703662994667839220546583581/62500000000000000000000000000000000000');
 
 ##############################################################################
 # bfac
@@ -279,7 +279,7 @@
 
 # square root with exact result
 $x = $cr->new('1.44');
-ok ($x->copy()->broot(2), '12/10');
+ok ($x->copy()->broot(2), '6/5');
 ok (ref($x->copy()->broot(2)), $cr);
 
 # log with exact result
@@ -312,6 +312,19 @@
 ok ($x, '64', 'from_oct');
 
 ##############################################################################
+# as_float()
+
+$x = Math::BigRat->new('1/2'); my $f = $x->as_float();
+
+ok ($x, '1/2', '$x unmodified');
+ok ($f, '0.5', 'as_float(0.5)');
+
+$x = Math::BigRat->new('2/3'); $f = $x->as_float(5);
+
+ok ($x, '2/3', '$x unmodified');
+ok ($f, '0.66667', 'as_float(2/3,5)');
+
+##############################################################################
 # done
 
 1;

==== //depot/perl/lib/Math/BigRat/t/bigroot.t#2 (text) ====
Index: perl/lib/Math/BigRat/t/bigroot.t
--- perl/lib/Math/BigRat/t/bigroot.t#1~31629~   2007-07-18 11:52:12.000000000 
-0700
+++ perl/lib/Math/BigRat/t/bigroot.t    2008-04-11 03:53:40.000000000 -0700
@@ -34,7 +34,7 @@
     }
   print "# INC = @INC\n";
 
-  plan tests => 4 * 2;
+  plan tests => 8 * 2;
   }
 
 use Math::BigFloat;
@@ -46,11 +46,10 @@
 # 2 ** 240 = 
 # 1766847064778384329583297500742918515827483896875618958121606201292619776
 
-# takes way too long
-#test_broot ('2','240', 8, undef,   '1073741824');
-#test_broot ('2','240', 9, undef,   
'106528681.3099908308759836475139583940127');
-#test_broot ('2','120', 9, undef,   
'10321.27324073880096577298929482324664787');
-#test_broot ('2','120', 17, undef,   
'133.3268493632747279600707813049418888729');
+test_broot ('2','240', 8, undef,   '1073741824');
+test_broot ('2','240', 9, undef,   
'106528681.3099908308759836475139583940127');
+test_broot ('2','120', 9, undef,   
'10321.27324073880096577298929482324664787');
+test_broot ('2','120', 17, undef,   
'133.3268493632747279600707813049418888729');
 
 test_broot ('2','120', 8, undef,   '32768');
 test_broot ('2','60', 8, undef,   '181.0193359837561662466161566988413540569');

==== //depot/perl/lib/Math/BigRat/t/hang.t#1 (text) ====
Index: perl/lib/Math/BigRat/t/hang.t
--- /dev/null   2008-03-18 12:45:05.529577733 -0700
+++ perl/lib/Math/BigRat/t/hang.t       2008-04-11 03:53:40.000000000 -0700
@@ -0,0 +1,27 @@
+#!/usr/bin/perl -w
+
+# test for bug #34584: hang in exp(1/2)
+
+use strict;
+use Test::More;
+
+BEGIN 
+  {
+  $| = 1;
+  chdir 't' if -d 't';
+  unshift @INC, '../lib'; # for running manually
+  plan tests => 1;
+  }
+
+use Math::BigRat;
+
+my $result = Math::BigRat->new('1/2')->bexp();
+
+is ("$result", 
"9535900335500879457687887524133067574481/5783815921445270815783609372070483523265",
+    "exp(1/2) worked");
+
+##############################################################################
+# done
+
+1;
+
End of Patch.

Reply via email to