This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[Patch] Math::BigInt v1.76, Math::BigRat v0.15, bignum v0.17
[perl5.git] / lib / Math / BigFloat.pm
index 8143175..2300ae4 100644 (file)
@@ -12,7 +12,7 @@ package Math::BigFloat;
 #   _a : accuracy
 #   _p : precision
 
-$VERSION = '1.49';
+$VERSION = '1.50';
 require 5.005;
 
 require Exporter;
@@ -47,7 +47,7 @@ $upgrade = undef;
 $downgrade = undef;
 # the package we are using for our private parts, defaults to:
 # Math::BigInt->config()->{lib}
-my $MBI = 'Math::BigInt::Calc';
+my $MBI = 'Math::BigInt::FastCalc';
 
 # are NaNs ok? (otherwise it dies when encountering an NaN) set w/ config()
 $_trap_nan = 0;
@@ -135,16 +135,12 @@ sub new
   # else: got a string
 
   # handle '+inf', '-inf' first
-  if ($wanted =~ /^[+-]?inf$/)
+  if ($wanted =~ /^[+-]?inf\z/)
     {
     return $downgrade->new($wanted) if $downgrade;
 
-    $self->{_e} = $MBI->_zero();
-    $self->{_es} = '+';
-    $self->{_m} = $MBI->_zero();
-    $self->{sign} = $wanted;
-    $self->{sign} = '+inf' if $self->{sign} eq 'inf';
-    return $self->bnorm();
+    $self->{sign} = $wanted;           # set a default sign for bstr()
+    return $self->binf($wanted);
     }
 
   # shortcut for simple forms like '12' that neither have trailing nor leading
@@ -1345,11 +1341,14 @@ sub bdiv
 
   my $xsign = $x->{sign};
   $y->{sign} =~ tr/+-/-+/;
-  my $y_not_one = !$y->is_one();       # cache this result
+
+  # check that $y is not 1 nor -1 and cache the result:
+  my $y_not_one = !($MBI->_is_zero($y->{_e}) && $MBI->_is_one($y->{_m}));
+
   if ($xsign ne $x->{sign})
     {
     # special case of $x /= $x results in 1
-    $x->bone();
+    $x->bone();                        # "fixes" also sign of $y, since $x is $y
     }
   else
     {
@@ -1443,7 +1442,10 @@ sub bmod
     return $x->bnan() if $x->is_zero();
     return $x;
     }
-  return $x->bzero() if $y->is_one() || $x->is_zero();
+
+  return $x->bzero() if $x->is_zero() ||
+  # check that $y == -1 or +1:
+    ($MBI->_is_zero($y->{_e}) && $MBI->_is_one($y->{_m}));
 
   my $cmp = $x->bacmp($y);                     # equal or $x < $y?
   return $x->bzero($a,$p) if $cmp == 0;                # $x == $y => result 0
@@ -2716,28 +2718,27 @@ This might change in the future, so do not depend on it.
 
 See also: L<Rounding|Rounding>.
 
-Math::BigFloat supports both precision and accuracy. For a full documentation,
-examples and tips on these topics please see the large section in
-L<Math::BigInt>.
+Math::BigFloat supports both precision (rounding to a certain place before or
+after the dot) and accuracy (rounding to a certain number of digits). For a
+full documentation, examples and tips on these topics please see the large
+section about rounding in L<Math::BigInt>.
 
-Since things like sqrt(2) or 1/3 must presented with a limited precision lest
-a operation consumes all resources, each operation produces no more than
-the requested number of digits.
+Since things like C<sqrt(2)> or C<1 / 3> must presented with a limited
+accuracy lest a operation consumes all resources, each operation produces
+no more than the requested number of digits.
 
-Please refer to BigInt's documentation for the precedence rules of which
-accuracy/precision setting will be used.
-
-If there is no gloabl precision set, B<and> the operation inquestion was not
-called with a requested precision or accuracy, B<and> the input $x has no
-accuracy or precision set, then a fallback parameter will be used. For
-historical reasons, it is called C<div_scale> and can be accessed via:
+If there is no gloabl precision or accuracy set, B<and> the operation in
+question was not called with a requested precision or accuracy, B<and> the
+input $x has no accuracy or precision set, then a fallback parameter will
+be used. For historical reasons, it is called C<div_scale> and can be accessed
+via:
 
        $d = Math::BigFloat->div_scale();               # query
        Math::BigFloat->div_scale($n);                  # set to $n digits
 
-The default value is 40 digits.
+The default value for C<div_scale> is 40.
 
-In case the result of one operation has more precision than specified,
+In case the result of one operation has more digits than specified,
 it is rounded. The rounding mode taken is either the default mode, or the one
 supplied to the operation after the I<scale>:
 
@@ -2751,8 +2752,8 @@ supplied to the operation after the I<scale>:
 
 Note that C<< Math::BigFloat->accuracy() >> and C<< Math::BigFloat->precision() >>
 set the global variables, and thus B<any> newly created number will be subject
-to the global rounding. This means that in the examples above, the C<3>
-as argument to C<bdiv()> will also get an accuracy of B<5>.
+to the global rounding B<immidiately>. This means that in the examples above, the
+C<3> as argument to C<bdiv()> will also get an accuracy of B<5>.
 
 It is less confusing to either calculate the result fully, and afterwards
 round it explicitely, or use the additional parameters to the math
@@ -2821,9 +2822,48 @@ C<as_number()>:
        $x = Math::BigFloat->new(2.5);
        $y = $x->as_number('odd');      # $y = 3
 
-=head1 EXAMPLES
-  # not ready yet
+=head1 METHODS
+
+=head2 accuracy
+
+        $x->accuracy(5);                # local for $x
+        CLASS->accuracy(5);             # global for all members of CLASS
+                                        # Note: This also applies to new()!
+
+        $A = $x->accuracy();            # read out accuracy that affects $x
+        $A = CLASS->accuracy();         # read out global accuracy
+
+Set or get the global or local accuracy, aka how many significant digits the
+results have. If you set a global accuracy, then this also applies to new()!
+
+Warning! The accuracy I<sticks>, e.g. once you created a number under the
+influence of C<< CLASS->accuracy($A) >>, all results from math operations with
+that number will also be rounded.
+
+In most cases, you should probably round the results explicitely using one of
+L<round()>, L<bround()> or L<bfround()> or by passing the desired accuracy
+to the math operation as additional parameter:
+
+        my $x = Math::BigInt->new(30000);
+        my $y = Math::BigInt->new(7);
+        print scalar $x->copy()->bdiv($y, 2);           # print 4300
+        print scalar $x->copy()->bdiv($y)->bround(2);   # print 4300
+
+=head2 precision()
+
+        $x->precision(-2);      # local for $x, round at the second digit right of the dot
+        $x->precision(2);       # ditto, round at the second digit left of the dot
+
+        CLASS->precision(5);    # Global for all members of CLASS
+                                # This also applies to new()!
+        CLASS->precision(-5);   # ditto
+
+        $P = CLASS->precision();        # read out global precision
+        $P = $x->precision();           # read out precision that affects $x
+
+Note: You probably want to use L<accuracy()> instead. With L<accuracy> you
+set the number of digits each result should have, with L<precision> you
+set the place where to round!
 
 =head1 Autocreating constants
 
@@ -3031,6 +3071,49 @@ C<badd()> etc. The first will modify $x, the second one won't:
        print $x->bpow($i),"\n";        # ditto
        print $x ** $i,"\n";            # leave $x alone 
 
+=item precision() vs. accuracy()
+
+A common pitfall is to use L<precision()> when you want to round a result to
+a certain number of digits:
+
+       use Math::BigFloat;
+
+       Math::BigFloat->precision(4);           # does not do what you think it does
+       my $x = Math::BigFloat->new(12345);     # rounds $x to "12000"!
+       print "$x\n";                           # print "12000"
+       my $y = Math::BigFloat->new(3);         # rounds $y to "0"!
+       print "$y\n";                           # print "0"
+       $z = $x / $y;                           # 12000 / 0 => NaN!
+       print "$z\n";
+       print $z->precision(),"\n";             # 4
+
+Replacing L<precision> with L<accuracy> is probably not what you want, either:
+
+       use Math::BigFloat;
+
+       Math::BigFloat->accuracy(4);            # enables global rounding:
+       my $x = Math::BigFloat->new(123456);    # rounded immidiately to "12350"
+       print "$x\n";                           # print "123500"
+       my $y = Math::BigFloat->new(3);         # rounded to "3
+       print "$y\n";                           # print "3"
+       print $z = $x->copy()->bdiv($y),"\n";   # 41170
+       print $z->accuracy(),"\n";              # 4
+
+What you want to use instead is:
+
+       use Math::BigFloat;
+
+       my $x = Math::BigFloat->new(123456);    # no rounding
+       print "$x\n";                           # print "123456"
+       my $y = Math::BigFloat->new(3);         # no rounding
+       print "$y\n";                           # print "3"
+       print $z = $x->copy()->bdiv($y,4),"\n"; # 41150
+       print $z->accuracy(),"\n";              # undef
+
+In addition to computing what you expected, the last example also does B<not>
+"taint" the result with an accuracy or precision setting, which would
+influence any further operation.
+
 =back
 
 =head1 SEE ALSO