diff options
Diffstat (limited to 'systems/texlive/tlnet/tlpkg/tlperl/lib/bigrat.pm')
-rw-r--r-- | systems/texlive/tlnet/tlpkg/tlperl/lib/bigrat.pm | 914 |
1 files changed, 567 insertions, 347 deletions
diff --git a/systems/texlive/tlnet/tlpkg/tlperl/lib/bigrat.pm b/systems/texlive/tlnet/tlpkg/tlperl/lib/bigrat.pm index 0a981471b2..8dabb93f11 100644 --- a/systems/texlive/tlnet/tlpkg/tlperl/lib/bigrat.pm +++ b/systems/texlive/tlnet/tlpkg/tlperl/lib/bigrat.pm @@ -1,63 +1,41 @@ package bigrat; -use 5.010; use strict; use warnings; -our $VERSION = '0.51'; +use Carp qw< carp croak >; + +our $VERSION = '0.66'; use Exporter; -our @ISA = qw( bigint ); +our @ISA = qw( Exporter ); our @EXPORT_OK = qw( PI e bpi bexp hex oct ); our @EXPORT = qw( inf NaN ); use overload; -use bigint (); + +my $obj_class = "Math::BigRat"; ############################################################################## -BEGIN { - *inf = \&bigint::inf; - *NaN = \&bigint::NaN; - *hex = \&bigint::hex; - *oct = \&bigint::oct; +sub accuracy { + my $self = shift; + $obj_class -> accuracy(@_); } -# These are all alike, and thus faked by AUTOLOAD - -my @faked = qw/round_mode accuracy precision div_scale/; -our ($AUTOLOAD, $_lite); # _lite for testsuite - -sub AUTOLOAD { - my $name = $AUTOLOAD; - - $name =~ s/.*:://; # split package - no strict 'refs'; - foreach my $n (@faked) { - if ($n eq $name) { - *{"bigrat::$name"} = - sub { - my $self = shift; - no strict 'refs'; - if (defined $_[0]) { - Math::BigInt->$name($_[0]); - Math::BigFloat->$name($_[0]); - return Math::BigRat->$name($_[0]); - } - return Math::BigInt->$name(); - }; - return &$name; - } - } +sub precision { + my $self = shift; + $obj_class -> precision(@_); +} - # delayed load of Carp and avoid recursion - require Carp; - Carp::croak ("Can't call bigrat\-\>$name, not a valid method"); +sub round_mode { + my $self = shift; + $obj_class -> round_mode(@_); } -sub unimport { - $^H{bigrat} = undef; # no longer in effect - overload::remove_constant('binary', '', 'float', '', 'integer'); +sub div_scale { + my $self = shift; + $obj_class -> div_scale(@_); } sub in_effect { @@ -66,150 +44,346 @@ sub in_effect { $hinthash->{bigrat}; } +sub _float_constant { + my $str = shift; + + # See if we can convert the input string to a string using a normalized form + # consisting of the significand as a signed integer, the character "e", and + # the exponent as a signed integer, e.g., "+0e+0", "+314e-2", and "-1e+3". + + my $nstr; + + if ( + # See if it is an octal number. An octal number like '0377' is also + # accepted by the functions parsing decimal and hexadecimal numbers, so + # handle octal numbers before decimal and hexadecimal numbers. + + $str =~ /^0(?:[Oo]|_*[0-7])/ and + $nstr = Math::BigInt -> oct_str_to_dec_flt_str($str) + + or + + # See if it is decimal number. + + $nstr = Math::BigInt -> dec_str_to_dec_flt_str($str) + + or + + # See if it is a hexadecimal number. Every hexadecimal number has a + # prefix, but the functions parsing numbers don't require it, so check + # to see if it actually is a hexadecimal number. + + $str =~ /^0[Xx]/ and + $nstr = Math::BigInt -> hex_str_to_dec_flt_str($str) + + or + + # See if it is a binary numbers. Every binary number has a prefix, but + # the functions parsing numbers don't require it, so check to see if it + # actually is a binary number. + + $str =~ /^0[Bb]/ and + $nstr = Math::BigInt -> bin_str_to_dec_flt_str($str)) + { + return $obj_class -> new($nstr); + } + + # If we get here, there is a bug in the code above this point. + + warn "Internal error: unable to handle literal constant '$str'.", + " This is a bug, so please report this to the module author."; + return $obj_class -> bnan(); +} + ############################################################################# +# the following two routines are for "use bigrat qw/hex oct/;": -sub import { - my $self = shift; +use constant LEXICAL => $] > 5.009004; + +# Internal function with the same semantics as CORE::hex(). This function is +# not used directly, but rather by other front-end functions. + +sub _hex_core { + my $str = shift; + + # Strip off, clean, and parse as much as we can from the beginning. + + my $x; + if ($str =~ s/ ^ ( 0? [xX] )? ( [0-9a-fA-F]* ( _ [0-9a-fA-F]+ )* ) //x) { + my $chrs = $2; + $chrs =~ tr/_//d; + $chrs = '0' unless CORE::length $chrs; + $x = $obj_class -> from_hex($chrs); + } else { + $x = $obj_class -> bzero(); + } + + # Warn about trailing garbage. + + if (CORE::length($str)) { + require Carp; + Carp::carp(sprintf("Illegal hexadecimal digit '%s' ignored", + substr($str, 0, 1))); + } - # see also bignum->import() for additional comments + return $x; +} + +# Internal function with the same semantics as CORE::oct(). This function is +# not used directly, but rather by other front-end functions. + +sub _oct_core { + my $str = shift; + + $str =~ s/^\s*//; + + # Hexadecimal input. + + return _hex_core($str) if $str =~ /^0?[xX]/; + + my $x; - $^H{bigrat} = 1; # we are in effect + # Binary input. + + if ($str =~ /^0?[bB]/) { + + # Strip off, clean, and parse as much as we can from the beginning. + + if ($str =~ s/ ^ ( 0? [bB] )? ( [01]* ( _ [01]+ )* ) //x) { + my $chrs = $2; + $chrs =~ tr/_//d; + $chrs = '0' unless CORE::length $chrs; + $x = $obj_class -> from_bin($chrs); + } + + # Warn about trailing garbage. + + if (CORE::length($str)) { + require Carp; + Carp::carp(sprintf("Illegal binary digit '%s' ignored", + substr($str, 0, 1))); + } + + return $x; + } + + # Octal input. Strip off, clean, and parse as much as we can from the + # beginning. + + if ($str =~ s/ ^ ( 0? [oO] )? ( [0-7]* ( _ [0-7]+ )* ) //x) { + my $chrs = $2; + $chrs =~ tr/_//d; + $chrs = '0' unless CORE::length $chrs; + $x = $obj_class -> from_oct($chrs); + } + + # Warn about trailing garbage. CORE::oct() only warns about 8 and 9, but it + # is more helpful to warn about all invalid digits. + + if (CORE::length($str)) { + require Carp; + Carp::carp(sprintf("Illegal octal digit '%s' ignored", + substr($str, 0, 1))); + } + + return $x; +} + +{ + my $proto = LEXICAL ? '_' : ';$'; + eval ' +sub hex(' . $proto . ') {' . <<'.'; + my $str = @_ ? $_[0] : $_; + _hex_core($str); +} +. + + eval ' +sub oct(' . $proto . ') {' . <<'.'; + my $str = @_ ? $_[0] : $_; + _oct_core($str); +} +. +} + +############################################################################# +# the following two routines are for Perl 5.9.4 or later and are lexical + +my ($prev_oct, $prev_hex, $overridden); + +if (LEXICAL) { eval <<'.' } +sub _hex(_) { + my $hh = (caller 0)[10]; + return $$hh{bigrat} ? bigrat::_hex_core($_[0]) + : $$hh{bigfloat} ? bigfloat::_hex_core($_[0]) + : $$hh{bigint} ? bigint::_hex_core($_[0]) + : $prev_hex ? &$prev_hex($_[0]) + : CORE::hex($_[0]); +} + +sub _oct(_) { + my $hh = (caller 0)[10]; + return $$hh{bigrat} ? bigrat::_oct_core($_[0]) + : $$hh{bigfloat} ? bigfloat::_oct_core($_[0]) + : $$hh{bigint} ? bigint::_oct_core($_[0]) + : $prev_oct ? &$prev_oct($_[0]) + : CORE::oct($_[0]); +} +. + +sub _override { + return if $overridden; + $prev_oct = *CORE::GLOBAL::oct{CODE}; + $prev_hex = *CORE::GLOBAL::hex{CODE}; + no warnings 'redefine'; + *CORE::GLOBAL::oct = \&_oct; + *CORE::GLOBAL::hex = \&_hex; + $overridden = 1; +} + +sub unimport { + $^H{bigrat} = undef; # no longer in effect + overload::remove_constant('binary', '', 'float', '', 'integer'); +} + +sub import { + my $class = shift; + + $^H{bigrat} = 1; # we are in effect + $^H{bigint} = undef; + $^H{bigfloat} = undef; # for newer Perls always override hex() and oct() with a lexical version: - if ($] > 5.009004) { - bigint::_override(); + if (LEXICAL) { + _override(); } - # some defaults - my $lib = ''; - my $lib_kind = 'try'; - my $upgrade = 'Math::BigFloat'; - - my @import = (':constant'); # drive it w/ constant - my @a = @_; - my $l = scalar @_; - my $j = 0; - my ($a, $p); - my ($ver, $trace); # version? trace? - for (my $i = 0; $i < $l ; $i++, $j++) { - if ($_[$i] eq 'upgrade') { - # this causes upgrading - $upgrade = $_[$i + 1]; # or undef to disable - my $s = 2; - $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." - splice @a, $j, $s; - $j -= $s; + + my @import = (); + my @a = (); # unrecognized arguments + my $ver; # version? + + while (@_) { + my $param = shift; + + # Accuracy. + + if ($param =~ /^a(ccuracy)?$/) { + push @import, 'accuracy', shift(); + next; } - elsif ($_[$i] =~ /^(l|lib|try|only)$/) { - # this causes a different low lib to take care... - $lib_kind = $1; - $lib_kind = 'lib' if $lib_kind eq 'l'; - $lib = $_[$i + 1] || ''; - my $s = 2; - $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." - splice @a, $j, $s; - $j -= $s; - $i++; + + # Precision. + + if ($param =~ /^p(recision)?$/) { + push @import, 'precision', shift(); + next; } - elsif ($_[$i] =~ /^(a|accuracy)$/) { - $a = $_[$i + 1]; - my $s = 2; - $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." - splice @a, $j, $s; - $j -= $s; - $i++; + + # Rounding mode. + + if ($param eq 'round_mode') { + push @import, 'round_mode', shift(); + next; } - elsif ($_[$i] =~ /^(p|precision)$/) { - $p = $_[$i + 1]; - my $s = 2; - $s = 1 if @a - $j < 2; # avoid "can not modify non-existent..." - splice @a, $j, $s; - $j -= $s; - $i++; + + # Backend library. + + if ($param =~ /^(l|lib|try|only)$/) { + push @import, $param eq 'l' ? 'lib' : $param; + push @import, shift() if @_; + next; } - elsif ($_[$i] =~ /^(v|version)$/) { + + if ($param =~ /^(v|version)$/) { $ver = 1; - splice @a, $j, 1; - $j--; + next; } - elsif ($_[$i] =~ /^(t|trace)$/) { - $trace = 1; - splice @a, $j, 1; - $j--; - } - elsif ($_[$i] !~ /^(PI|e|bpi|bexp|hex|oct)\z/) { - die ("unknown option $_[$i]"); + + if ($param =~ /^(t|trace)$/) { + $obj_class .= "::Trace"; + eval "require $obj_class"; + die $@ if $@; + next; } - } - my $class; - $_lite = 0; # using M::BI::L ? - if ($trace) { - require Math::BigInt::Trace; - $class = 'Math::BigInt::Trace'; - $upgrade = 'Math::BigFloat::Trace'; - } - else { - # see if we can find Math::BigInt::Lite - if (!defined $a && !defined $p) { # rounding won't work to well - local @INC = @INC; - pop @INC if $INC[-1] eq '.'; - if (eval { require Math::BigInt::Lite; 1 }) { - @import = (); # :constant in Lite, not MBI - Math::BigInt::Lite->import(':constant'); - $_lite = 1; # signal okay - } + + if ($param =~ /^(PI|e|bexp|bpi|hex|oct)\z/) { + push @a, $param; + next; } - require Math::BigInt if $_lite == 0; # not already loaded? - $class = 'Math::BigInt'; # regardless of MBIL or not + + croak("Unknown option '$param'"); } - push @import, $lib_kind => $lib if $lib ne ''; - # Math::BigInt::Trace or plain Math::BigInt - $class->import(@import, upgrade => $upgrade); - require Math::BigFloat; - Math::BigFloat->import(upgrade => 'Math::BigRat', ':constant'); - require Math::BigRat; - Math::BigRat->import(@import); + eval "require $obj_class"; + die $@ if $@; + $obj_class -> import(@import); - bigrat->accuracy($a) if defined $a; - bigrat->precision($p) if defined $p; if ($ver) { - print "bigrat\t\t\t v$VERSION\n"; - print "Math::BigInt::Lite\t v$Math::BigInt::Lite::VERSION\n" if $_lite; - print "Math::BigInt\t\t v$Math::BigInt::VERSION"; - my $config = Math::BigInt->config(); - print " lib => $config->{lib} v$config->{lib_version}\n"; - print "Math::BigFloat\t\t v$Math::BigFloat::VERSION\n"; - print "Math::BigRat\t\t v$Math::BigRat::VERSION\n"; + printf "%-31s v%s\n", $class, $class -> VERSION(); + printf " lib => %-23s v%s\n", + $obj_class -> config("lib"), $obj_class -> config("lib_version"); + printf "%-31s v%s\n", $obj_class, $obj_class -> VERSION(); exit; } - # Take care of octal/hexadecimal constants - overload::constant binary => - sub { - bigint::_binary_constant(shift); - }; + $class -> export_to_level(1, $class, @a); # export inf, NaN, etc. - # if another big* was already loaded: - my ($package) = caller(); + overload::constant - no strict 'refs'; - if (!defined *{"${package}::inf"}) { - $self->export_to_level(1, $self, @a); # export inf and NaN - } + # This takes care each number written as decimal integer and within the + # range of what perl can represent as an integer, e.g., "314", but not + # "3141592653589793238462643383279502884197169399375105820974944592307". + + integer => sub { + #printf "Value '%s' handled by the 'integer' sub.\n", $_[0]; + my $str = shift; + return $obj_class -> new($str); + }, + + # This takes care of each number written with a decimal point and/or + # using floating point notation, e.g., "3.", "3.0", "3.14e+2" (decimal), + # "0b1.101p+2" (binary), "03.14p+2" and "0o3.14p+2" (octal), and + # "0x3.14p+2" (hexadecimal). + + float => sub { + #printf "# Value '%s' handled by the 'float' sub.\n", $_[0]; + _float_constant(shift); + }, + + # Take care of each number written as an integer (no decimal point or + # exponent) using binary, octal, or hexadecimal notation, e.g., "0b101" + # (binary), "0314" and "0o314" (octal), and "0x314" (hexadecimal). + + binary => sub { + #printf "# Value '%s' handled by the 'binary' sub.\n", $_[0]; + my $str = shift; + return $obj_class -> new($str) if $str =~ /^0[XxBb]/; + $obj_class -> from_oct($str); + }; } -sub PI () { Math::BigFloat->new('3.141592653589793238462643383279502884197'); } -sub e () { Math::BigFloat->new('2.718281828459045235360287471352662497757'); } +sub inf () { $obj_class -> binf(); } +sub NaN () { $obj_class -> bnan(); } + +# This should depend on the current accuracy/precision. Fixme! +sub PI () { $obj_class -> new('3.141592653589793238462643383279502884197'); } +sub e () { $obj_class -> new('2.718281828459045235360287471352662497757'); } sub bpi ($) { - local $Math::BigFloat::upgrade; - Math::BigFloat->bpi(@_); + my $up = Math::BigFloat -> upgrade(); # get current upgrading, if any ... + Math::BigFloat -> upgrade(undef); # ... and disable + my $x = Math::BigFloat -> bpi(@_); + Math::BigFloat -> upgrade($up); # reset the upgrading + return $obj_class -> new($x); } sub bexp ($$) { - local $Math::BigFloat::upgrade; - my $x = Math::BigFloat->new($_[0]); - $x->bexp($_[1]); + my $up = Math::BigFloat -> upgrade(); # get current upgrading, if any ... + Math::BigFloat -> upgrade(undef); # ... and disable + my $x = Math::BigFloat -> new(shift); + $x -> bexp(@_); + Math::BigFloat -> upgrade($up); # reset the upgrading + return $obj_class -> new($x); } 1; @@ -220,279 +394,291 @@ __END__ =head1 NAME -bigrat - Transparent BigNumber/BigRational support for Perl +bigrat - transparent big rational number support for Perl =head1 SYNOPSIS - use bigrat; + use bigrat; - print 2 + 4.5,"\n"; # BigFloat 6.5 - print 1/3 + 1/4,"\n"; # produces 7/12 + print 2 + 4.5; # Math::BigRat 13/2 + print 1/3 + 1/4; # Math::BigRat 7/12 + print inf + 42; # Math::BigRat inf + print NaN * 7; # Math::BigRat NaN + print hex("0x1234567890123490"); # Perl v5.10.0 or later - { - no bigrat; - print 1/3,"\n"; # 0.33333... - } + { + no bigrat; + print 1/3; # 0.33333... + } - # Import into current package: - use bigrat qw/hex oct/; - print hex("0x1234567890123490"),"\n"; - print oct("01234567890123490"),"\n"; + # for older Perls, import into current package: + use bigrat qw/hex oct/; + print hex("0x1234567890123490"); + print oct("01234567890123490"); =head1 DESCRIPTION -All operators (including basic math operations) are overloaded. Integer and -floating-point constants are created as proper BigInts or BigFloats, -respectively. +All numeric literal in the given scope are converted to Math::BigRat objects. -Other than L<bignum>, this module upgrades to Math::BigRat, meaning that -instead of 2.5 you will get 2+1/2 as output. +All operators (including basic math operations) except the range operator C<..> +are overloaded. -=head2 Modules Used +So, the following: -C<bigrat> is just a thin wrapper around various modules of the Math::BigInt -family. Think of it as the head of the family, who runs the shop, and orders -the others to do the work. + use bigrat; + $x = 1234; -The following modules are currently used by bignum: +creates a Math::BigRat and stores a reference to in $x. This happens +transparently and behind your back, so to speak. - Math::BigInt::Lite (for speed, and only if it is loadable) - Math::BigInt - Math::BigFloat - Math::BigRat +You can see this with the following: -=head2 Math Library + perl -Mbigrat -le 'print ref(1234)' -Math with the numbers is done (by default) by a module called -Math::BigInt::Calc. This is equivalent to saying: +Since numbers are actually objects, you can call all the usual methods from +Math::BigRat on them. This even works to some extent on expressions: - use bigrat lib => 'Calc'; + perl -Mbigrat -le '$x = 1234; print $x->bdec()' + perl -Mbigrat -le 'print 1234->copy()->binc();' + perl -Mbigrat -le 'print 1234->copy()->binc->badd(6);' + perl -Mbigrat -le 'print +(1234)->copy()->binc()' -You can change this by using: +(Note that print doesn't do what you expect if the expression starts with +'(' hence the C<+>) - use bignum lib => 'GMP'; +You can even chain the operations together as usual: -The following would first try to find Math::BigInt::Foo, then -Math::BigInt::Bar, and when this also fails, revert to Math::BigInt::Calc: + perl -Mbigrat -le 'print 1234->copy()->binc->badd(6);' + 1241 - use bigrat lib => 'Foo,Math::BigInt::Bar'; +Please note the following does not work as expected (prints nothing), since +overloading of '..' is not yet possible in Perl (as of v5.8.0): -Using C<lib> warns if none of the specified libraries can be found and -L<Math::BigInt> did fall back to one of the default libraries. -To suppress this warning, use C<try> instead: + perl -Mbigrat -le 'for (1..2) { print ref($_); }' - use bignum try => 'GMP'; +=head2 Options -If you want the code to die instead of falling back, use C<only> instead: +C<bigrat> recognizes some options that can be passed while loading it via +C<use>. The following options exist: - use bignum only => 'GMP'; +=over 4 -Please see respective module documentation for further details. +=item a or accuracy -=head2 Sign +This sets the accuracy for all math operations. The argument must be greater +than or equal to zero. See Math::BigInt's bround() method for details. -The sign is either '+', '-', 'NaN', '+inf' or '-inf'. + perl -Mbigrat=a,50 -le 'print sqrt(20)' -A sign of 'NaN' is used to represent the result when input arguments are not -numbers or as a result of 0/0. '+inf' and '-inf' represent plus respectively -minus infinity. You will get '+inf' when dividing a positive number by 0, and -'-inf' when dividing any negative number by 0. +Note that setting precision and accuracy at the same time is not possible. -=head2 Methods +=item p or precision -Since all numbers are not objects, you can use all functions that are part of -the BigInt or BigFloat API. It is wise to use only the bxxx() notation, and not -the fxxx() notation, though. This makes you independent on the fact that the -underlying object might morph into a different class than BigFloat. +This sets the precision for all math operations. The argument can be any +integer. Negative values mean a fixed number of digits after the dot, while a +positive value rounds to this digit left from the dot. 0 means round to integer. +See Math::BigInt's bfround() method for details. -=over 2 + perl -Mbigrat=p,-50 -le 'print sqrt(20)' -=item inf() +Note that setting precision and accuracy at the same time is not possible. -A shortcut to return Math::BigInt->binf(). Useful because Perl does not always -handle bareword C<inf> properly. +=item t or trace -=item NaN() +This enables a trace mode and is primarily for debugging. -A shortcut to return Math::BigInt->bnan(). Useful because Perl does not always -handle bareword C<NaN> properly. +=item l, lib, try, or only -=item e +Load a different math lib, see L<Math Library>. - # perl -Mbigrat=e -wle 'print e' + perl -Mbigrat=l,GMP -e 'print 2 ** 512' + perl -Mbigrat=lib,GMP -e 'print 2 ** 512' + perl -Mbigrat=try,GMP -e 'print 2 ** 512' + perl -Mbigrat=only,GMP -e 'print 2 ** 512' -Returns Euler's number C<e>, aka exp(1). +=item hex -=item PI +Override the built-in hex() method with a version that can handle big numbers. +This overrides it by exporting it to the current package. Under Perl v5.10.0 and +higher, this is not so necessary, as hex() is lexically overridden in the +current scope whenever the C<bigrat> pragma is active. - # perl -Mbigrat=PI -wle 'print PI' +=item oct -Returns PI. +Override the built-in oct() method with a version that can handle big numbers. +This overrides it by exporting it to the current package. Under Perl v5.10.0 and +higher, this is not so necessary, as oct() is lexically overridden in the +current scope whenever the C<bigrat> pragma is active. -=item bexp() +=item v or version - bexp($power,$accuracy); +this prints out the name and version of the modules and then exits. -Returns Euler's number C<e> raised to the appropriate power, to -the wanted accuracy. + perl -Mbigrat=v -Example: +=back - # perl -Mbigrat=bexp -wle 'print bexp(1,80)' +=head2 Math Library -=item bpi() +Math with the numbers is done (by default) by a backend library module called +Math::BigInt::Calc. The default is equivalent to saying: - bpi($accuracy); + use bigrat lib => 'Calc'; -Returns PI to the wanted accuracy. +you can change this by using: -Example: + use bigrat lib => 'GMP'; - # perl -Mbigrat=bpi -wle 'print bpi(80)' +The following would first try to find Math::BigInt::Foo, then Math::BigInt::Bar, +and if this also fails, revert to Math::BigInt::Calc: -=item upgrade() + use bigrat lib => 'Foo,Math::BigInt::Bar'; -Return the class that numbers are upgraded to, is in fact returning -C<$Math::BigInt::upgrade>. +Using c<lib> warns if none of the specified libraries can be found and +L<Math::BigInt> fell back to one of the default libraries. To suppress this +warning, use c<try> instead: -=item in_effect() + use bigrat try => 'GMP'; - use bigrat; +If you want the code to die instead of falling back, use C<only> instead: - print "in effect\n" if bigrat::in_effect; # true - { - no bigrat; - print "in effect\n" if bigrat::in_effect; # false - } + use bigrat only => 'GMP'; -Returns true or false if C<bigrat> is in effect in the current scope. +Please see the respective module documentation for further details. -This method only works on Perl v5.9.4 or later. +=head2 Method calls -=back +Since all numbers are now objects, you can use all methods that are part of the +Math::BigRat API. -=head2 MATH LIBRARY +But a warning is in order. When using the following to make a copy of a number, +only a shallow copy will be made. -Math with the numbers is done (by default) by a module called + $x = 9; $y = $x; + $x = $y = 7; -=head2 Caveat +Using the copy or the original with overloaded math is okay, e.g., the following +work: -But a warning is in order. When using the following to make a copy of a number, -only a shallow copy will be made. + $x = 9; $y = $x; + print $x + 1, " ", $y,"\n"; # prints 10 9 - $x = 9; $y = $x; - $x = $y = 7; +but calling any method that modifies the number directly will result in B<both> +the original and the copy being destroyed: -If you want to make a real copy, use the following: + $x = 9; $y = $x; + print $x->badd(1), " ", $y,"\n"; # prints 10 10 - $y = $x->copy(); + $x = 9; $y = $x; + print $x->binc(1), " ", $y,"\n"; # prints 10 10 -Using the copy or the original with overloaded math is okay, e.g. the -following work: + $x = 9; $y = $x; + print $x->bmul(2), " ", $y,"\n"; # prints 18 18 - $x = 9; $y = $x; - print $x + 1, " ", $y,"\n"; # prints 10 9 +Using methods that do not modify, but test that the contents works: -but calling any method that modifies the number directly will result in -B<both> the original and the copy being destroyed: + $x = 9; $y = $x; + $z = 9 if $x->is_zero(); # works fine - $x = 9; $y = $x; - print $x->badd(1), " ", $y,"\n"; # prints 10 10 +See the documentation about the copy constructor and C<=> in overload, as well +as the documentation in Math::BigFloat for further details. - $x = 9; $y = $x; - print $x->binc(1), " ", $y,"\n"; # prints 10 10 +=head2 Methods - $x = 9; $y = $x; - print $x->bmul(2), " ", $y,"\n"; # prints 18 18 +=over 4 -Using methods that do not modify, but testthe contents works: +=item inf() - $x = 9; $y = $x; - $z = 9 if $x->is_zero(); # works fine +A shortcut to return Math::BigRat->binf(). Useful because Perl does not always +handle bareword C<inf> properly. -See the documentation about the copy constructor and C<=> in overload, as -well as the documentation in BigInt for further details. +=item NaN() -=head2 Options +A shortcut to return Math::BigRat->bnan(). Useful because Perl does not always +handle bareword C<NaN> properly. -bignum recognizes some options that can be passed while loading it via use. -The options can (currently) be either a single letter form, or the long form. -The following options exist: +=item e -=over 2 + # perl -Mbigrat=e -wle 'print e' -=item a or accuracy +Returns Euler's number C<e>, aka exp(1). -This sets the accuracy for all math operations. The argument must be greater -than or equal to zero. See Math::BigInt's bround() function for details. +=item PI - perl -Mbigrat=a,50 -le 'print sqrt(20)' + # perl -Mbigrat=PI -wle 'print PI' -Note that setting precision and accuracy at the same time is not possible. +Returns PI. -=item p or precision +=item bexp() -This sets the precision for all math operations. The argument can be any -integer. Negative values mean a fixed number of digits after the dot, while -a positive value rounds to this digit left from the dot. 0 or 1 mean round to -integer. See Math::BigInt's bfround() function for details. + bexp($power, $accuracy); - perl -Mbigrat=p,-50 -le 'print sqrt(20)' +Returns Euler's number C<e> raised to the appropriate power, to the wanted +accuracy. -Note that setting precision and accuracy at the same time is not possible. +Example: -=item t or trace + # perl -Mbigrat=bexp -wle 'print bexp(1,80)' + +=item bpi() -This enables a trace mode and is primarily for debugging bignum or -Math::BigInt/Math::BigFloat. + bpi($accuracy); -=item l or lib +Returns PI to the wanted accuracy. -Load a different math lib, see L<MATH LIBRARY>. +Example: - perl -Mbigrat=l,GMP -e 'print 2 ** 512' + # perl -Mbigrat=bpi -wle 'print bpi(80)' -Currently there is no way to specify more than one library on the command -line. This means the following does not work: +=item accuracy() - perl -Mbignum=l,GMP,Pari -e 'print 2 ** 512' +Set or get the accuracy. -This will be hopefully fixed soon ;) +=item precision() -=item hex +Set or get the precision. -Override the built-in hex() method with a version that can handle big -numbers. This overrides it by exporting it to the current package. Under -Perl v5.10.0 and higher, this is not so necessary, as hex() is lexically -overridden in the current scope whenever the bigrat pragma is active. +=item round_mode() -=item oct +Set or get the rounding mode. -Override the built-in oct() method with a version that can handle big -numbers. This overrides it by exporting it to the current package. Under -Perl v5.10.0 and higher, this is not so necessary, as oct() is lexically -overridden in the current scope whenever the bigrat pragma is active. +=item div_scale() -=item v or version +Set or get the division scale. -This prints out the name and version of all modules used and then exits. +=item in_effect() + + use bigrat; + + print "in effect\n" if bigrat::in_effect; # true + { + no bigrat; + print "in effect\n" if bigrat::in_effect; # false + } + +Returns true or false if C<bigrat> is in effect in the current scope. - perl -Mbigrat=v +This method only works on Perl v5.9.4 or later. =back =head1 CAVEATS -=over 2 +=over 4 + +=item Hexadecimal, octal, and binary floating point literals + +Perl (and this module) accepts hexadecimal, octal, and binary floating point +literals, but use them with care with Perl versions before v5.32.0, because some +versions of Perl silently give the wrong result. =item Operator vs literal overloading -C<bigrat> works by overloading handling of integer and floating point -literals, converting them to L<Math::BigInt> or L<Math::BigRat> -objects. +C<bigrat> works by overloading handling of integer and floating point literals, +converting them to L<Math::BigRat> objects. -This means that arithmetic involving only string values or string -literals will be performed using Perl's built-in operators. +This means that arithmetic involving only string values or string literals are +performed using Perl's built-in operators. For example: @@ -501,59 +687,72 @@ For example: my $y = "900000000000000007"; print $x - $y; -will output C<0> on default 32-bit builds, since C<bigrat> never sees -the string literals. To ensure the expression is all treated as -C<Math::BigInt> or C<Math::BigRat> objects, use a literal number in -the expression: +outputs C<0> on default 32-bit builds, since C<bigrat> never sees the string +literals. To ensure the expression is all treated as C<Math::BigRat> objects, +use a literal number in the expression: print +(0+$x) - $y; +=item Ranges + +Perl does not allow overloading of ranges, so you can neither safely use ranges +with C<bigrat> endpoints, nor is the iterator variable a C<Math::BigRat>. + + use 5.010; + for my $i (12..13) { + for my $j (20..21) { + say $i ** $j; # produces a floating-point number, + # not an object + } + } + =item in_effect() This method only works on Perl v5.9.4 or later. =item hex()/oct() -C<bigint> overrides these routines with versions that can also handle -big integer values. Under Perl prior to version v5.9.4, however, this -will not happen unless you specifically ask for it with the two -import tags "hex" and "oct" - and then it will be global and cannot be -disabled inside a scope with "no bigint": +C<bigrat> overrides these routines with versions that can also handle big +integer values. Under Perl prior to version v5.9.4, however, this will not +happen unless you specifically ask for it with the two import tags "hex" and +"oct" - and then it will be global and cannot be disabled inside a scope with +C<no bigrat>: - use bigint qw/hex oct/; + use bigrat qw/hex oct/; + print hex("0x1234567890123456"); + { + no bigrat; print hex("0x1234567890123456"); - { - no bigint; - print hex("0x1234567890123456"); - } + } The second call to hex() will warn about a non-portable constant. Compare this to: - use bigint; + use bigrat; - # will warn only under Perl older than v5.9.4 - print hex("0x1234567890123456"); + # will warn only under Perl older than v5.9.4 + print hex("0x1234567890123456"); =back =head1 EXAMPLES - perl -Mbigrat -le 'print sqrt(33)' - perl -Mbigrat -le 'print 2*255' - perl -Mbigrat -le 'print 4.5+2*255' - perl -Mbigrat -le 'print 3/7 + 5/7 + 8/3' - perl -Mbigrat -le 'print 12->is_odd()'; - perl -Mbignum=l,GMP -le 'print 7 ** 7777' + perl -Mbigrat -le 'print sqrt(33)' + perl -Mbigrat -le 'print 2**255' + perl -Mbigrat -le 'print 4.5+2**255' + perl -Mbigrat -le 'print 3/7 + 5/7 + 8/3' + perl -Mbigrat -le 'print 12->is_odd()'; + perl -Mbigrat=l,GMP -le 'print 7 ** 7777' =head1 BUGS -For information about bugs and how to report them, see the BUGS section in the -documentation available with the perldoc command. - - perldoc bignum +Please report any bugs or feature requests to +C<bug-bignum at rt.cpan.org>, or through the web interface at +L<https://rt.cpan.org/Ticket/Create.html?Queue=bignum> (requires login). +We will be notified, and then you'll automatically be notified of +progress on your bug as I make changes. =head1 SUPPORT @@ -561,10 +760,31 @@ You can find documentation for this module with the perldoc command. perldoc bigrat -For more information, see the SUPPORT section in the documentation available -with the perldoc command. +You can also look for information at: - perldoc bignum +=over 4 + +=item * GitHub + +L<https://github.com/pjacklam/p5-bignum> + +=item * RT: CPAN's request tracker + +L<https://rt.cpan.org/Dist/Display.html?Name=bignum> + +=item * MetaCPAN + +L<https://metacpan.org/release/bignum> + +=item * CPAN Testers Matrix + +L<http://matrix.cpantesters.org/?dist=bignum> + +=item * CPAN Ratings + +L<https://cpanratings.perl.org/dist/bignum> + +=back =head1 LICENSE @@ -588,7 +808,7 @@ L<Math::BigInt::FastCalc>, L<Math::BigInt::Pari> and L<Math::BigInt::GMP>. =item * -Peter John Acklam E<lt>pjacklam@gmail.com<gt>, 2014-. +Maintained by Peter John Acklam E<lt>pjacklam@gmail.comE<gt>, 2014-. =back |