Math-BigInt-1.999829/0000755403072340010010000000000014163520623014003 5ustar OSPJADomain UsersMath-BigInt-1.999829/BUGS0000644403072340010010000000355214156375570014506 0ustar OSPJADomain UsersFor an updated list of bugs, see
https://rt.cpan.org/Public/Dist/Display.html?Name=Math-BigInt
The following list is not up to date:
Known bugs:
* TODO BUGS:
+ implement test for the upgrading bug in bsub()
* NaN handling in comparisons slightly broken. See also [perl #33106].
* General:
+ BigInt can not the IEEE '-0'. Currently there are no plans to add this. If
you need it, please bug the author(s) about it.
* BigFloat:
+ comparing (<=> or == or !=) a BigFloat to a BigInt don't work yet
+ new is first running the entire number trough _split, then again the parts
to construct BigInts. Could be a bit more optimized.
+ fdiv() using F (fallback) mode does not work properly in all cases of
local (aka $x's or $y's) A or P settings. Not definite test case yet, but
it might calculate not enough digits to satisfy the rounding needs.
* BigInt:
+ exponent on input is limited to a Perl int (bigger numbers won't fit
into your memory, anyway - use BigFloat)
+ doesn't have a mode akin to 'use integer;', e.g. it always emulates Perl
(this is solved partially by use bigint ;)
+ Handling of undef arguments is somewhat broken (no proper warnings)
+ eval('use...') and use Math::BigInt qw/:constant/ fail on Perl prior 5.6.0
This is likely an Exporter bug, and causes Math::BigInt to eval require on
earlier Perls when loading the core math lib. Thus the loading can fail
under older Perls on filesystems that can not cope with the
'Math/BigInt/Calc.pm'-style filenames.
###############################################################################
Mixing of classes does not always work like expected. "use bignum;",
"use bigint;" and "use bigrat;" should solve this problem for most cases.
Please send me test-reports, your experiences with this and your ideas - I love
to hear about my work!
Tels
Math-BigInt-1.999829/CHANGES0000644403072340010010000027026214163402151015002 0ustar OSPJADomain Users1.999829 2021-12-29
* Improve methods div_scale() and round_mode() so they work better with
subclasses. This fixes CPAN RT #125430.
* Make div_scale() accept a Math::Big(Int|Float|Rat) object as input. This
fixes CPAN RT #140599.
1.999828 2021-12-17
* Add new methods numerator(), denominator(), and fparts().
* Fix bug in to_ieee754(). Avoid that the significand overflows.
* Improve bpow(). Avoid unnecessary upgrading.
* Fix typos and improve wording.
1.999827 2021-10-03
* Improve error message for missing library argument.
* Skip tests that don't work on older Perls. Also skip tests that compare
floating point numbers.
1.999826 2021-10-01
* Improve documentation related to floating point literals.
* Skip tests that fail due to Perl's broken handling of floating point literals
before v5.32.0.
1.999825 2021-09-28
* Make Math::BigInt accept integers regardless of whether they are written as
decimal, binary, octal, or hexadecimal integers or decimal, binary, octal, or
hexadecimal floating point number.
* When numeric constants are overloaded (with the ":constant" option) in
Math::BigInt, every numeric constant that represent an integer is converted
to an object regardless of how it is written. All finite non-integers are
converted to a NaN.
* When numeric constants are overloaded (with the ":constant" option) in
Math::BigFloat, every numeric constant is converted to an object regardless
of how it is written.
* Add method from_dec() (cf. from_bin(), from_oct(), and from_hex()). It is
like new() except that it does not accept anything but a string representing a
finite decimal number.
1.999824 2021-09-20
* Don't allow mixing math libraries. Use the first backend math library that is
successfully loaded, and ignore any further attempts at loading a different
backend library. This is a solution to the re-occurring problem of using
objects using different math libraries.
* Add missing documentation.
* Miscellaneous minor improvements.
1.999823 2021-07-12
* Improve the handling of the backend libraries. Provide more useful warnings
and error messages. Update the documentation.
1.999822 2021-07-09
* Make the from_hex(), from_oct(), and from_bin() methods consistent with
CORE::oct(), which does not require a leading "0" before the letter ("x",
"o", or "b").
* Make the from_oct() and new() methods accept octal numbers with prefix
"0o", "0O", "o" (lowercase letter o), and "O" (capital letter O).
* Make the from_bin() and new() methods accept binary numbers with
prefix "0b", "0B", "b", and "B".
* Make the from_hex() and new() methods accept hexadecimal numbers with
prefix "0x", "0X", "x", and "X".
* Update test files to match with the above.
1.999821 2021-07-06
* Make new() and from_hex() accept the "0X" prefix, not just the "0x" prefix,
but not accept just "X" or "x". Now, "0XFF" returns 255, not NaN.
* Make new() and from_bin() accept the "0B" prefix, not just the "0b" prefix, but
not accept just "B" or "b". Now, "0B1111" returns 255, not NaN.
* Make new() and from_oct() accept the "0o" and "0O" prefixes, but not accept
just "O" (capital letter O) or "o" (lowercase letter o). Now, "0o377" and
"0O377" return 255, not NaN. Also intepret floating point numbers with a
leading zero and a binary exponent as an octal number, so that "01.4p0"
returns 1.5, not NaN. There is still no ambiguety, since decimal floating
point numbers use "e" or "E" before the exponent, and binary and hexadecimal
floating point numbers use a "0b"/"0B" or "0x"/"0x" prefix, respectively.
1.999820 2021-07-06
* Fix bug and improve error messages in Math::BigInt::import().
1.999819 2021-07-02
* Add method btfac() (triple factorial) and bmfac() (multi-factorial),
including tests and documentation.
* Add missing and correct erroneous documentation for bfac() (factorial)
and bdfac() (double factorial). Also correct handling of special cases
and add tests for these cases.
* Fix error in bsin() and bcos() causing them to hang indefinitely if the
invocand is +/-inf.
* Make it possible for the end user to specify the base length used internally
in Math::BigInt::Calc.
1.999818 2019-10-20
* Fix CPAN RT #130736 regarding numify() on a Math::BigFloat with a large
number of digits and an equally large, but negative, exponent.
* Fix a problem in to_ieee754() due to rounding in bpow().
1.999817 2019-10-11
* Avoid non-integers in intermediate computations in Math::BigInt::Calc. This
causes errors due to rounding issues, e.g., 47265625999999999 / 1000000000
is 47265626 with double precision.
* Remove api_version() and the corresponding test file. There is no need to
check which methods are supported by a backend library now that each backend
library is a subclass of Math::BigInt::Lib. Methods not provided in the
backend library are provided by the parent class.
* Add to_ieee745() and from_ieee754().
* Add backermann() and ackermann() for the Ackermann function.
* Add buparrow() and uparrow() for Knuth's up-arrow notation.
* Add information about the github repository.
* Update links in SUPPORT section in POD.
* Fix bpow(). It returned NaN when it should truncate to zero.
* Make blsft() in Math::BigInt allow bases up until the largest unsigned
integer.
* Make _lsft() in Math::BigInt::Calc handle an arbitrarily large base.
* Add new methods bdigitsum() and digitsum() to Math::BigInt. Add new method
_digitsum() to Math::BigInt::Lib.
* Add new methods is_non_negative() and is_non_positive().
* Extend the default collation sequence used by to_base() and from_base() to
all the 94 printable ASCII characters except blank/space.
* Make new() in Math::BigFloat handle octal floating point numbers.
* Slightly more robust t/01load.t.
* Remove unused variables.
* Miscellaneous code cleanup.
1.999816 2018-10-26
* bnok() for Math::BigInt and Math::BigFloat now support the full Kronenburg
extension. The behaviour is identical to the behaviour of the Maple and
Mathematica function for negative integers n, k. Add tests. This closes CPAN
RT #95628.
* Fix POD errors. This closes CPAN RT #125141.
1.999815 2018-10-19
* Move bitwise operators signed and, signed or, and signed xor from
lib/Math/BigInt/CalcEmu.pm into lib/Math/BigInt/Lib.pm. The file
lib/Math/BigInt/CalcEmu.pm is no longer needed and thus removed.
1.999814 2018-10-01
* Add to_base() and from_base() to Math::BigInt and corresponding library
methods _to_base() and _from_base() to Math::BigInt::Lib. This was inspired
by CPAN RT #122681.
* Fix Makefile.PL to reflect that Test::More is only needed for testing, not
for building.
* In the documentation for each of the to_(bin|hex|oct|bytes) methods, add a
reference to the corresponding from_(bin|hex|oct|bytes) method.
1.999813 2018-04-18
* Fix CPAN RT #125108. Remove test files try.pl, t/author-bpi-big-mbf.t, and
t/release-unused-vars.t, which were included in the 1.999812 distribution by
accident.
1.999812 2018-04-17
* Fix CPAN RT #120351 regarding bpow(). Add test.
* Fix CPAN RT #120717 regarding tests now that '.' is not in @INC by default.
* Fix CPAN RT #122756 regarding testing for 64 bit integer support.
* Fix case when both accuracy and precision are set, resulting in a NaN. This
closes CPAN RT #124790.
* Fix typo in one of the change log entries for version 1.999811.
* Clearify documentation of rounding modes.
* Update the documentation of configuration parameters.
* Fix rounding and accuracy in bpi(). Extra digits in intermediate computation
were not used, causing the last digits to be inaccurate. In addition, the
rounding was incorrect in some cases.
* Use config() as a method, rather than a function. Also use config("xyz")
rather than config()->{xyz}.
* Correct more of the problems with rounding in the constructors. If rounding
arguments are given as arguments to the constructor, the constructor should
assign those values to the instance. If no rounding arguments are given, and
the constructor is called as a class method, the class rounding variables
should be assigned to the instance. Added test file
t/author-constructors-a-p-r.t to replace t/author-constructors-a-p.t, but
lots of tests are failing and (for now) commented out.
* Remove statements used for debugging.
* Fix typos.
* Cleaner log/exp-related code in Math::BigFloat.
* Remove unused variables.
* Add test file t/release-portability.t.
* Add test file t/release-whitespaces.t.
* Convert test file t/02pod.t to t/release-pod.t and t/03podcov.t to
t/release-pod-coverage.t.
* Reformat CHANGES to match the specification in CPAN::Changes::Spec and
CPAN::Meta::Spec.
* Expand tabs to spaces and clean up whitepace.
* Include tests that were previously commented out.
* Use $LIB as the variable name for backend math library.
* Import "carp" and "croak" from the Carp module.
* Math::BigInt isa Exporter, so Math::BigInt should require Exporter.
Math::BigFloat has Math::BigInt in @ISA, so it doesn't need to require
Exporter.
* Don't load Test::More when it isn't really needed. This speeds up processing
of author test files when they are skipped.
1.999811 2017-03-15 pjacklam
* Fix an old bug in the Math::BigFloat methods as_hex(), as_oct(), and
as_bin() methods resulting in loss of accuracy. This bug was introduced in
bug in Math-BigInt-1.76. Due to a naive copy and paste by me, and lack of
tests, this bug was also present in the newer to_hex(), to_oct(), and
to_bin() methods. This shows the bug, as it did not print "0xffff...":
print Math::BigFloat -> from_hex("f" x 30) -> as_hex();
* Fix incorrect formatting in the output from the Math::BigFloat methods
to_hex(), to_oct(), and to_bin() when the output was zero. A prefix was
added when it shouldn't have been.
* Add tests to bigintpm.inc and bigfltpm.inc for better testing of as_hex(),
as_oct(), and as_bin() as well as to_hex(), to_oct(), and to_bin().
* "Synchronize" tests and code formatting in bigintpm.inc and bigfltpm.inc.
1.999810 2017-03-01 pjacklam
* CPAN RT #120240 revealed that the problems with undefined values is still
present. After a close examination, I believe the only way to get this
really working is to to make blog() call objectify() differently depending
on whether the base for the logarithm is undefined or not. That way we can
avoid objectify() converting the undefined value to a zero. Ideally, we
should warn about undefined values when used in any other context, but we'll
handle that in a later release. See also the related changelog entry for
v1.999801.
* Fix the way the argument count is computed in objectify(). When an argument
count of 0 is given, it means that we should objectify all input arguments.
However, it turned out that the actual argument count was computed
incorrectly.
* Fix CPAN RT #120242 rearding c3 method resolution.
1.999809 2017-02-10 pjacklam
* When a new method is added to Math::BigInt or Math::BigFloat, and this new
method requires a new backend library method, die with a suitable error
message if the installed backend library does not support this new method.
The error message says that the method requires a newer version of the
backend library.
* Fix typos in Math::BigFloat and Math::BigInt.
* Add bfib() and blucas() to Math::BigInt. They return Fibonacci and Lucas
numbers, respectively. The actual computation of the numbers is done by the
backend library. Documented both methods in POD. Add test files bfib-mbi.t
and blucas-mbi.t.
* Add _fib() and _lucas() to Math::BigInt::Lib. They return Fibonacci and
Lucas numbers, respectively. Document both methods in POD. Add test files
author-lib-arithmetic-unary-_fib.t and author-lib-arithmetic-unary-_lucas.t.
1.999808 2017-01-11 pjacklam
* In Math::BigInt and Math::BigFloat, add methods bdfac() for double
factorial. Add tests for this method.
* In Math::BigInt and Math::BigFloat, add methods to_hex(), to_oct(), and
to_bin() for hexadecimal, octal, and binary string output without prefix.
Even for Math::BigFloat there is still only support for integer output. Add
tests for these methods.
* Add test for as_oct() corresponding to the old tests for as_hex() and
as_bin().
* In Math::BigInt::Lib, add method _dfac() for double factorial. Add
corresponding tests.
* In Math::BigInt::Lib, fix bug in overloaded "int".
* In Math::BigInt::Lib, implement much faster versions of _from_hex(),
_from_oct(), and _from_bin().
* In Makefile.PL, improve the wording in the message displayed if some of
the installed backend libraries are not a subclass of Math::BigInt::Lib (and
hence will not provide
* Fix minor bugs in some of the author library test files (t/author-lib*.t).
* Allow leading and trailing whitespace in the input to from_hex(),
from_oct(), and from_bin(). Add tests to verify. This is a regressions
(CPAN RT #119805).
1.999807 2016-12-23 pjacklam
* Add a message to Makefile.PL recommending upgrade if old libraries are
installed. This message is more or less equivalent to the one appearing in
Math-BigInt up until v1.997.
* Improve the documentation (POD) in Math::BigInt::Lib.
* Speed up _sqrt() and _root() in Math::BigInt::Lib.
* Remove checking for exception cases (cases that would return +Inf, -Inf, or
NaN) in Math::BigInt::Lib. It has been documented for a long time that such
checking should be done by the caller.
* Add library methods _to_bin(), _to_oct(), _to_hex(), which are equivalent to
the _as_bin(), _as_oct(), and _as_hex() methods respectively, except that
the _to_*() methods don't use a prefix in the output. This removes the need
for the frequent removal of the various prefixes. Now each _as_*() method
calls the equivalent _to_*() method, adds a prefix, and returns the output.
The _to_*() methods are faster than the equivalent _as_*() methods were.
* Add author test files for the methods _to_bin(), _to_oct(), and _to_hex().
* Add library method _to_bytes(). The method _as_bytes() would have been
called _to_bytes() if I had thought of it earlier. The method _as_bytes() is
now just an alias to _to_bytes(). The _to_bytes() method also fixes a bug
that was present in the _as_bytes() method. (CPAN RT #119346).
* Add author test files for the method _to_bytes().
* Add more tests for library methods _inc() and _dec(). When trying to bring
the Math::BigInt::BitVect library back to life I realized that the test
suite didn't catch certain errors in _inc() and _dec().
* Die if trying to use as_bytes() or from_bytes() with a backend library that
doesn't support the corresponding library methods.
* Correct minor errors in the output messages in the test files.
* Improve/correct various comments in the source code.
* More diagnostic output is displayed by the author test files if the
AUTHOR_DEBUGGING environment variable is set.
1.999806 2016-12-13 pjacklam
* Add more logic to Makefile.PL regarding INSTALLDIRS (CPAN RT #119199
and #119225).
* In the TODO file, remove stuff that has been implemented.
1.999805 2016-12-11 pjacklam
* Fix Makefile.PL so that this module installs over the core version.
* Add more tests for _nok() (binomial coefficient "n over k"). These new tests
revealed some problems with some of the backend libraries when _nok() was
given very large arguments.
* Remove t/Math/BigFloat/#Subclass.pm#, which is an Emacs temporary file
included by accident.
1.999804 2016-12-07 pjacklam
* Implement as_bytes(), as requested (CPAN RT 119096). Also implement the
inverse conversion from_bytes(). This applies to Math::BigInt only. (Alas,
these methods will be inherited from Math::BigInt into Math::BigFloat,
Math::BigRat etc. where the methods won't work. Fixing this class
relationship is an issue of its own.)
* Implement _as_bytes() and _from_bytes() in Math::BigInt::Lib. Preferably,
the various backend libraries will implement faster versions of their
own. Add author test files for testing these methods thorougly.
* Fix from_hex(), from_oct(), and from_bin().
- When called as instance methods, the new value should be assigned to the
invocand unless the invocand is read-only (a constant).
- When called as instance methods, the assigned value was incorrect, if the
invocand was inf or NaN.
- Add tests to t/from_hex-mbf.t, t/from_oct-mbf.t, and t/from_bin-mbf.t
to confirm the fix.
- Add new test files t/from_hex-mbi.t, t/from_oct-mbi.t, and
t/from_bin-mbi.t for better testing of these methods with Math::BigInt.
* Correct typo in Math/BigInt/Lib.pm (otherise -> otherwise) (CPAN RT 118829).
* Add POD coverage testing of Math::BigInt::Lib to t/03podcov.t.
1.999803 2016-12-03 pjacklam
* Remove BENCHMARK file. The information was obsolete.
* Use ExtUtils::MakeMaker rather than Module::Install in Makefile.PL
* Reorder CHANGES file (this file) so the newest entries appear at the top.
* Fix error in test information text in various author test files.
* Remove author information in LICENSE file.
* Inform that the TODO file is not up to date.
1.999802 2016-11-28 pjacklam
* When bzero(), bone(), binf(), and bnan() are used as constructors, don't
check whether the class allows the object to be modified. A constructor
isn't modifying any existing object. This applies to both Math::BigInt and
Math::BigFloat.
* Improve bgcd() and blcm(). This applies to both Math::BigInt and
Math::BigFloat.
1.999801 2016-11-23 pjacklam
* Fix, hopefully once and for all, the longstanding problem of handling undef
as an operand to mathematical methods. The only method that accepts undef as
an operand is blog(), where the second operand might be undef, as in
$x->blog() or $x->blog($b), where $b is undef. The undef signifies that
Euler's number should be used as the base. With this fix, we should be able
to get Math::BigInt::Lite working again.
* Add least common multiple method _lcm() to Math::BigInt::Lib, and add
corresponding test file t/author-lib-arithmetic-binary-_lcm.t and test data
file t/author-lib-arithmetic-binary-_lcm.dat.
* Remove internal function __lcm() which has become redundant now that _lcm()
is in the library.
* Make it possible to use bgcd() and blcm() as class methods, since other
methods can be used as class methods. This applies to both Math::BigInt and
Math::BigFloat.
* Fix blcm() with negative input. The LCM should always be non-negative. This
applies to both Math::BigInt and Math::BigFloat.
* Add tests for bgcd() and blcm() in t/bigintpm.t and t/bigfltpm.t.
* Fix tests for blcm() assuming that LCM(0,0) should be a NaN. LCM(0,0) is 0
by convention.
* Prefer Class->config('option') over Class->config()->{option}. However, this
does not seem to be working for all options. It seems that this won't work
properly until we move the global variables into the OO interface.
* Explicitly specify the library in all test files that are shared between
Math-BigInt and the library distributions (FaatCalc, GMP, Pari, ...) with,
e.g., "use Math::BigInt only => 'Calc';". This way, it will fail immediately
if the specified library can't be loaded rather than using the fallback
library.
1.999800 2016-11-15 pjacklam
* Upgrade bundled Module::Install from version 1.16 to version 1.17.
* Add Math::BigInt::Lib (lib/Math/BigInt/Lib.pm), a parent class for
Math::BigInt backend libraries.
* Use objects in Math::BigInt::Calc, not just array refs. Also use OO-style,
i.e., use $class->_add($x, $y) rather than _add($class, $x, $y).
* Not all library methods modify the invocand, so call library methods as,
e.g, $x = $LIB->method($x, $y) rather than just $LIB->method($x, $y).
* Math::BigInt::Calc is now a subclass of Math::BigInt::Lib.
* Add Math::BigInt::Lib::Minimal (t/Math/BigInt/Lib/Minimal.pm) for testing
inheritance from Math::BigInt::Lib.
* Minor simplification in Math::BigInt::Calc->_str().
* Speed up Math::BigInt::Calc->_root().
* Remove test files that were included in the previous release by accident.
* Add more tests and use more verbose output in some tests.
* Fix typo in lib/Math/BigFloat.pm
* Fix documentation error in lib/Math/Calc.pm
* Use Config::Tiny and an .ini file to handle the library specific
configuration for the author-lib*.t test files.
1.999727 2016-11-04 pjacklam
* Skip test exceeding the range of VAX floating point number in t/bigintpm.inc
(CPAN RT 118468).
* Fix typo in lib/Math/BigInt.pm (CPAN RT 118550).
1.999726 2016-07-15 pjacklam
* Re-insert Math::BigFloat->DESTROY, which was accidentally removed in
v1.999725.
1.999725 2016-07-13 pjacklam
Changes:
* Add method is_finite().
* In Math::BigInt and Math::BigFloat, remove warnings about deprecated usage,
at least until we have removed this usage from the "bignum" distribution.
These warnings were too annoying for some people.
Improvements:
* Faster bnok() when the library (backend) does not support it.
* In the Math::BigFloat method bpi(), use a precomputed list of digits when
the accuracy is <= 1000. This speeds up the trigonometric functions
considerably, when I will introduce range reduction in a later release. This
makes the _atan_inv() method redundant, so remove it. Also, the _alen()
library method is now only used in _log_int(), which is good, because it
isn't clear from the docs and tests what it was supposed to do.
Fixes:
* Fix bug in the Math::BigInt::Calc library method _digit(). It would
sometimes return undef or an empty string when it should have returned zero.
* Fix bug in the Math::BigInt::Calc library method _rsft(). It would sometimes
return two output arguments.
* Fix bug in the Math::BigInt::Calc library method _lsft(). When the number
zero was shifted N places in base 10, the result was not zero, but an
invalid object.
* Fix bug in the Math::BigInt::Calc library methods _and(), _or(), and _xor().
They always assigned zero to the first input argument (the invocand).
* Improve the Math::BigInt::Calc library method _log_int() for the cases when
the output is zero or one. Also simplify the code.
* Simplify the code for the Math::BigInt::Calc library method _zeros().
* Reformat Math::BigInt::Calc so it is easier to read, for me anyway.
* Add file t/author-bnok-mbi.t
* Add one test file for every method in the libraries, including
t/Math/BigInt/Lib/TestUtil.pm with test utilities.
* Clean up whitespace in all files in the distribution.
* Better testing in t/author-bpi-mbf.t
* The Math::BigInt::Calc library now always uses integers inside the objects,
so there is no longer any need for all the "0 + ..." to convert strings to
numbers, and the "int()" inside "length(int(...))" to determine the length
of an array element. The only case that needs "0 + ..." now is the
constructor _new(), whose input is a string.
Note, however, that the Math::BigInt::FastCalc library method _new() still
creates objects with leading zeros, so until that is fixed, we can't remove
all the "0 + ..." etc. until Math::BigInt::FastCalc has been modified.
1.999724 2016-06-19 pjacklam
* In Math/BigInt.pm and Math/BigFloat.pm, correct and improve to the
documentation, e.g., reorder the methods so that methods that belogin
together are grouped together.
* In Math/BigInt.pm and Math/BigFloat.pm, refactor the code so that methods
that belong together are grouped together. Also use consistent code
formatting.
* In Math/BigInt/Calc.pm, reformat the code.
1.999723 2016-06-09 pjacklam
* Add Math::BigInt and Math::BigFloat methods bnstr(), bestr(), and bdstr(),
as well as corresponding methods nparts(), eparts(), and dparts(). Also add
test files bdstr-mbf.t, bdstr-mbi.t, bestr-mbf.t, bestr-mbi.t, bnstr-mbf.t,
bnstr-mbi.t, bsstr-mbf.t, bsstr-mbi.t, dparts-mbf.t, dparts-mbi.t,
eparts-mbf.t, eparts-mbi.t, nparts-mbf.t, nparts-mbi.t, sparts-mbf.t, and
sparts-mbi.t.
* Fix documentation errors.
1.999722 2016-04-26 pjacklam
* Fix bug in bone() and binf() when used as a function. The error caused
warnings about using an unitialized variable. This fix applies to both
Math::BigInt and Math::BigFloat.
1.999721 2016-04-26 pjacklam
* Prevent Math::BigFloat methods band(), bior(), bxor(), and bnot() from
modifying unmodifiable objects.
1.999720 2016-04-26 pjacklam
* Overloaded 'int' should not modify it's argument.
* Better documentation of blsft() and brsft().
1.999719 2016-04-25 pjacklam
* Revert the change to Math::BigFloat's blsft() and brsft() methods, which
truncated the input (and output) to integers. However, now convert the base
to an object only when the base isn't an object already. Also return NaN if
any of the three operands is a NaN.
* Change t/bigfltpm.inc to reflect the changes to blsft() and brsft(). Also,
when a method should be tested, actually test that method, not the
overloaded operator, which doesn't necessarily behave in the exact same
manner as the method. This applies to the methods binc(), bdec(), bpow(),
badd(), bsub(), bmul(), bdiv() in scalar context, brsft(), blsft(), and
bmod().
* The first output argument from objectify() is the class name, so use the
variable name $class, not $self.
1.999718 2016-04-22 pjacklam
* Improve documentation on large, unquoted input values to Math::BigInt.
* Remove stuff from bitfltpm.inc that was placed into author-numify-mbf.t, but
accidentally still present in bitfltpm.inc. Adjusted test counts as needed.
* Fix file headers in author-bmod-bdiv-mbi.t and author-btmod-btdiv-mbi.t.
* Add bnan(), binf(), and bsub() methods to Math::BigFloat. This is a step
along the way to having Math::BigFloat no longer being a subclass of
Math::BigInt.
* Using bnan, binf(), bzero() and bone() as functions is deprecated. This is a
step along the way to a pure object oriented design.
* When bnan() and binf() are used as instance methods, they no longer delete
the accuracy and precision instance variables.
* Add test files from_bin-mbf.t, from_oct-mbf.t, and new-mbf.t.
* Remove some code for Perl prior to 5.6. Such old versions are no longer
support anyway.
* Fix buggy handling of NaN in bcmp().
* Add methods beq(), bne(), blt(), ble(), bgt(), and bge() to Math::BigInt and
Math::BigFloat. These methods are called for the overloaded operators.
* Add overloading of '==', '!=', '<', '<=', '>', to to Math::BigInt and
Math::BigFloat and fix the broken overloading of '>='. These overloaded
operators now behave like the equivalent core Perl operators.
* Add test file author-relop-mbi-mbf.t for testing bcmp(), beq(), bne(),
blt(), ble(), bgt(), and bge(), as well as the overloaded operators '==',
'!=', '<', '<=', '>', and '>='.
* 'int' now truncates a Math::BigFloat object to an integer without converting
it to a Math::BigInt. When an object becomes a Math::BigInt, further
computations with that object as invocand causes the arguments to be
converted to Math::BigInt objects too, leading to unexpected results. This
is confusing people. Unless downgrading is in effect, no Math::BigFloat
object should become a Math::BigInt unless a Math::BigInt is explicitly
requested.
* For Math::BigFloat, modify bitwise operations brsft() and brsft(), and add
band(), bior(), bxor(), and bnot(). These now handle floating point numbers
the same way as core Perl does, i.e., truncate non-integers to integers
before applying the bitwise operator. This change will also make Perl's
behaviour more consistent whether 'use bignum' is in effect or not.
* Add overloading of '~' (bitwise not). It just calls bnot(), which has been
implemented for ages.
* Fix error in POD for bone().
* Take parts of the code in t/calling.t and move it into the new files
t/calling-class-methods.t and t/calling-instance-methods.t.
* Improve test descriptions in t/mbimbf.inc.
1.999717 2016-04-16 pjacklam
* Using new() with an undefined argument no longer gives a warning. Explicit
use of this is discouraged, but it is sometimes used by the modules
themselves issuing warnings that is confusing to the end user. Just
uncomment the code, since we plan to reintroduce this warning later.
* Avoid using L<> around e-mail addressess in POD.
1.999716 2016-04-03 pjacklam
* $x->new(...) can no longer be used to assign a value to $x. This was a
mistake introduced in v1.999712. As the name "new" implies, it should always
return a new object.
* Using new() with no argument no longer gives a warning. This use has been
discouraged, in favour of bzero(), for many years, but people are still
using it, so I am reintroducing the support for this.
* Added btdiv() and btmod() for truncated division (T-division) and ditto
remainder. Add tests.
* Add test files author-bmod-bdiv-mbi.t author-btmod-btdiv-mbi.t with more
thorough testing of bdiv(), bmod(), btdiv(), and btmod().
* When new() is used as an instance method, the new object is initialized as a
copy of the invocand.
* Move test for numfiy() of +Inf, -Inf, NaN, and big integers from
bigfltpm.inc and bigintpm.inc into author-numify-mbi.t and
author-numify-mbf.t.
* Improved wording and fixed typos in earlier changelog entries.
1.999715 2016-01-05 pjacklam
* Fix Math::BigFloat->bexp() based on patch by DANAJ (Dana Jacobsen).
* Add Math::BigFloat->bexp() tests to "t/biglog.t" and new file
"t/author-bexp-mbf.t".
* Fix flawed test in test_bpow. It used ok($x, $y) rather than is($x, $y).
* Add better descriptions (test names) to a few tests.
* Wrap long line in the CHANGES file.
1.999714 2016-01-03 pjacklam
* Add code to speed up Math::BigFloat->batan(). Thanks to DANAJ (Dana
Jacobsen) for the patch.
* Re-write Math::BigFloat->batan2() completely, except for the parts related
to the rounding. The old version was sometimes correct, sometimes off by pi,
and sometimes very inaccurate. Also add more tests.
* Make it clearer in Math::BigFloat->bpi() when it is called as a method vs.
as a function.
* The Math::BigFloat->bpi() method can now be used as an instance method to
assign pi to $x, as in $x->bpi().
* Add tests for as_oct().
* Minor simplifications in Math::BigInt->as_oct() and
Math::BigInt::Calc::_as_oct().
1.999713 2015-12-31 pjacklam
* Fix Math::BigInt->new(), which had a faulty handling in the shortcut for
non-zero scalar integers with no non-zero exponent, like "12", "12.000",
"12e3", and "12.000e4". Added tests for this in t/bigintpm.inc.
1.999712 2015-12-29 pjacklam
* Fix bug in internal function _e_add() and _e_sub() which causes it to return
"-0" in some cases.
* Let new() be used for assignment. Now $x->new(3) assigns 3 to $x.
* Improve code in new() for non-zero scalar integers with no exponent.
* Allow both "inf" and "infinity". Allow a leading sign, and ignore letter
case. This is to be consistent with core Perl.
* Be more consistent about allowed whitespace in input. E.g., "23 " gave 23,
but "inf " gave a NaN.
* Core Perl allows both "0x" and "0X" as hexadecimal prefix, and both "0b" and
"0B" as binary prefix, so we do too. Previously, only 0x and 0b were
allowed.
* Math::BigFloat now has its own from_bin() method which supports binary
floating point numbers, e.g., "0b1.1001p-4". This complements from_hex().
* Math::BigFloat now has its own from_oct() method which supports octal
floating point numbers, e.g., "1.3267p-4". This complements from_hex().
* The Math::BigInt and Math::BigFloat methods from_hex(), from_oct(), and
from_bin() can now be used as instance methods to assign values to the
invocand, e.g, $x->from_oct("10") assigns 8 to $x.
* Update documentation. Perl now uses "Inf", not "inf" to represent infinity.
* When the new() method is called with an undefined argument, the round
parameters are now passed on to bzero(). This applies to both Math::BigInt
and Math::BigFloat.
* Replace "UNIVERSAL::isa($this, $that)" with "$this->isa($that)", and ditto
for "can()", where possible. Not every instance of "UNIVERSAL::Isa()" has
been replaced, though, since the change causes some tests to fail. This must
be looked into.
* Simplify the copy() methods. Always copy accuracy and precision parameters,
even when they are undefined.
* Reformat more of the code in accordancw with the "perlstyle" manual page.
This makes the code a lot easier to read -- for me, anyway.
* Use a more generic regex in t/calling.t, since the exact wording of the
error message depends not on the Perl version, but on the module that does
the version checking.
* Avoid infinite loop in the Math::BigFloat->batan() method. Thanks to DANAJ
(Dana Jacobsen) for the patch. This was not intended to be added before the
next release, but was included in this release by accident.
1.9997_11 2015-12-10 pjacklam
This release introduces no changes in the library code, i.e., the .pm files in
the 'lib' directory, but there are a lot of changes in the test files. Since
there are so many changes, I let this be a development release.
* Add 'use strict;' and 'use warnings;' to all test files.
* Reformat code in the test files according to the "perlstyle" manual page.
This makes the code a lot easier to read -- for me, anyway.
* Decrement required version of Perl from v5.6.2 to v5.6.1. All tests pass
when running the test suite with Perl 5.6.1 on Cygwin.
* Replace "use vars ..." with "our ..." in test files.
* Replace "BEGIN { unshift @INC, 't'; }" with "use lib 't';" in test files.
* Use "our $x; $x = ...;" rather than "our $x = ...;" since the latter causes
Perl 5.6.1 to complain about variables only used once.
* Add comment to all tests. Now the tests no longer says just "ok 123", but
rather "ok 123 - $x->blog(2)" etc. This makes it easier to identify failed
tests, especially in the smoke testing reports.
* Fix various flawed tests, e.g., ok($x, 2) was used testing whether $x was 2.
* Use the skip() feature of Test::More for skipping tests.
* Use more descriptive variable names in test files.
* Remove unused variables in test files.
* Move variable declarations to limit their scope in test files.
* Remove trailing whitespace in test files.
* Wrap (most) lines to fit 80 columns in test files.
1.999710 2015-11-12 pjacklam
* New method Math::BigFloat -> from_hex() which supports hexadecimal floating
point numbers, e.g., "0x1.999ap-4".
* New test file t/from_hex-mbf.t for testing Math::BigFloat -> from_hex().
* Add 'from_hex' and 'from_bin' to list of methods in the Math::BigInt POD.
1.999709 2015-11-06 pjacklam
* Represent and return zero as 0E0, not 0E1. The old POD said "A zero is
represented and returned as 0E1, not 0E0 (after Knuth)." I find no
references to Knuth ever having said this. The closest reference I can find
is that Knuth says 0**0 should be defined to be 1, not 0, but that is
something else than 0e0, which is 0*10**0. I have yet to see any other
mathematical software that represents and returns zero as 0e1 rather than
0e0.
* Required version of Test::More is 0.9301.
1.999708 2015-11-03 pjacklam
* Use bxxx() method names consistently, rather than mixing bxxx() and fxxx()
in code and test files. The fxxx() methods for Math::BigFloat objects are
still available through autoloading. However, we leave the fround() method
in Math::BigInt, as it seems to provide some kind of compatibility with
Math::BigFloat.
* Correct author information in the README file.
* Remove INSTALL file, which by accident wasn't removed in v1.999707.
* Use present tense, not past tense, in CHANGES file.
* Add '#!perl' to Makefile.PL for correct syntax highlighting in editors
supporting this.
* Use Math::Complex::Inf() in testfiles also (for generating Perl scalar
infinity) since it is more portable.
1.999707 2015-10-29 pjacklam
* Add dependency on Math::Complex 1.39 for Math::Complex::Inf(), which is
used for numifying infinity.
* Update author information.
* Update information in the file README.
* Remove the files INSTALL and LICENSE as this information is already covered
in the file README.
* Enable 'use warnings' in all modules. We require a Perl newer than 5.6.0
anyway.
* Replace 'use vars ...' with 'our ...'. We require a Perl newer than 5.6.0
anyway.
* Avoid indirect object syntax in documentation.
* Moved 'Test::More' from 'build_requires' to 'test_requires' in Makefile.PL.
1.999706 2015-10-28 pjacklam
* Correct release date of v1.999705 in CHANGES.
* Add code and tests for numify() on non-finite objects.
1.999705 2015-10-26 pjacklam
* Avoid using "my" in a false conditional. See "Deprecated use of my() in
false conditional" in perldiag(1).
* Faster algorithm for bpi() when accuracy is >= 1000.
1.999704 2015-09-25 pjacklam
* objectify() in lib/Math/BigInt.pm now uses 'isa' not 'eq' to check object
relationship. This is necessary for correct handling of subclasses.
* objectify() in lib/Math/BigInt.pm no longer expects as_int(), as_number()
and as_float() to return objects, but allows them to return numbers
formatted as strings. This is used by some other modules on CPAN.
* Better documentation of as_int() and as_number() in lib/Math/BigInt.pm.
* Add documentation for as_float() in lib/Math/BigFloat.pm
* Add test files t/objectify_mbf.t and t/objectify_mbi.t.
1.999703 2015-09-21 pjacklam
* Fix blog() in Math::BigInt and Math::BigFloat to work correctly regardless
of the base.
* Correct existing tests in bigintpm.inc and bigfltpm.inc.
* Update test plans (number of tests) in t/bare_mbi.t, t/bigintpm.t, and
t/sub_mbi.t.
* Add test files t/blog-mbf.t and t/blog-mbi.t for better testing of the
blog() methods.
1.999702 2015-09-17 pjacklam
* The overloaded log() is a unary operator, so don't pass additional
arguments.
* Fix blog() so the cases $x->blog() and $x->blog(undef) work correctly. An
undefined base means that blog() should use base e (Euler's number).
* Both CORE::log() and other mathematical software returns inf for log(inf),
so we do the same.
* Add tests for log() as well as templates for future tests of the other
overloadable functions.
* Improve descriptions of a few tests.
1.999701 2015-09-11 pjacklam
* The POD documentation, as well as the comments in the code, said that
$x->bdiv($y) in list context should return quotient $q and remainder $r so
that $x = $q * $y + $r, and that the remainder (modulo) $r should correspond
to Perl's % operator as well as the bmod() method. This has not been the
actual behaviour. This is now fixed. In scalar context, only the quotient is
returned.
* Clearer POD documentation for the bdiv() and bmod() methods.
* All non-integer input values to Math::BigInt gave a NaN, except non-zero
numbers in the range (-1,1) that were written without an exponent, e.g.,
"-0.75" and "0.5". Now also these return a NaN.
* Input values with a large (absolute value) negative exponent, e.g.,
1e-9999999, now return NaN. The former behaviour was to die with the message
"Quantifier in {,} bigger than 32766 in regex; marked by ..."
* Intermediate computations in blog() increased the number of digits
significantly in some cases. Now reduce the number of digits by rounding.
However, keep some extra digits for remaining intermediate computations
before the final rounding.
* When $x is a Math::BigFloat, $x -> bceil() and $x -> bint() for -1 < $x < 0
returned -0. Negative zero is never used by Math::Big(Int|Float), and care
has been taken to avoid it, so this bug is surely an oversight.
* Explicitly specify the backend (lib => 'Calc') in t/mbimbf.t for easier
release management of the backend distributions.
* Add "use warnings" to test scripts, since Perl 5.6.2 is required anyway, and
"use warnings" was introduced in Perl 5.6.1.
* Modified test scripts so the difference between the test files in the
Math-BigInt distribution and the backend distributions are as few and as
small as possible. This makes for easier release management.
1.9997 2015-08-12 pjacklam
CHANGES
* Add recent changes.
t/bigintpm.inc
* Correct spelling errors.
t/upgrade.inc
* Correct spelling errors.
1.9996 2015-08-12 pjacklam
CHANGES
* Add recent changes.
* Use present tense in change descriptions.
lib/Math/BigInt.pm
* Change incorrect use of ok() to is() in example.
1.9995 2015-08-11 pjacklam
CHANGES
* Move changes that were incorrectly reported as being for the release 1.9994
when they were in fact for release 1.9993.
* Add changes both for release 1.9994 and 1.9995.
lib/Math/BigInt.pm
* Break lines to avoid lines with more than 80 characters.
* Improve objectify() for better handling of subclasses.
1.9994 2015-08-10 pjacklam
CHANGES
* Add recent changes.
lib/Math/BigFloat.pm
* Fix blog() which sometimes returns incorrect result.
* bdiv() in list context now returns the integer quotient and the remainder.
t/bigfltpm.inc
* Modify tests for blog() in list context.
t/biglog.t
* Change incorrect use of ok() to is().
t/upgrade.inc
* Modify tests for blog() in list context.
inc/Module/Install*
* Upgrade bundled Module::Install from version 1.08 to version 1.16.
1.9993 2014-04-03 pjacklam
BUGS
* Add reference to CPAN RT for the Math-BigInt distro.
CHANGES
* Add recent changes.
examples/hailstone.pl
* Remove this file as it doesn't seem to be working.
lib/Math/BigFloat.pm
* Correct spelling errors.
* Reformat code to avoid long lines.
* Improve POD formatting.
* Add meta-documentation (CPAN ratings, CPAN testers matrix, etc.)
* Add the bint() method.
lib/Math/BigInt.pm
* Correct spelling errors.
* Reformat code to avoid long lines.
* Improve POD formatting.
* Add meta-documentation (CPAN ratings, CPAN testers matrix, etc.)
* Add the bint() method.
* Remove references to the obsolete Math::Big
lib/Math/BigInt/Calc.pm
* Correct spelling errors.
* Added meta-documentation (CPAN ratings, CPAN testers matrix, etc.)
lib/Math/BigInt/CalcEmu.pm
* Correct spelling errors.
* Improve POD formatting.
* Add meta-documentation (CPAN ratings, CPAN testers matrix, etc.)
* Remove references to Math::BigInt::BitVect, which is no longer on CPAN.
Makefile.PL
* Remove code that checks for compatible versions of distributions that
depend on Math-BigInt. Such checking should be done in the distributions
that depend on Math-BigInt, not in Math-BigInt itself.
NEW
* This file now only refers to the change log.
t/bigfltpm.inc
* Add tests for fint().
t/bigintpm.inc
* Add tests for int().
t/upgrade.inc
* Add tests for int().
t/*.t
* Increment test counts as needed for the new tests in the t/*.inc files.
inc/Module/Install*
* Upgrade bundled Module::Install from version 1.01 to version 1.08.
1.997 2011-09-04 pjacklam
* Document actual behaviour of from_xxx() methods. [perl #85334] (Peter John
Acklam)
* Make bmuladd() able to handle third arg properly. [perl #85482] (Peter John
Acklam)
* Add sign function bsgn() as a complement to babs(). (Peter John Acklam)
* Fix objectify()'s handling of "foreign objects". (RT #16221 and #52124)
(Peter John Acklam)
* Rewrap some verbatim pod in Math::BigInt. (Father Chrysostomos)
* Correct links to sections. (Alexandr Ciornii)
* Remove incorrect formatting inside verbatim paragraphs. (Alexandr Ciornii)
* Upgrade bundled modules in "inc" to latest version. (Peter John Acklam)
* Include "^MYMETA\.(yml|json)\z" in MANIFEST.SKIP. Whereas META.* are
generated by the distribution author at packaging time, MYMETA.* are
generated by the end user at configure time after any dynamic dependencies
are known. (Peter John Acklam)
1.993 2011-02-26 pjacklam
* Change default backend library from Math::BigInt::FastCalc to
Math::BigInt::Calc, which is included in the Math-BigInt distro. This
avoids recursive distribution dependency (RT #65976) (Peter John Acklam).
1.992 2011-02-18 pjacklam
* Math::BigInt::Calc->_nok(): Use symmetry property nok(n,k) = nok(n,n-k) to
speed up execution when k is large. Also general code cleanup. (Peter John
Acklam).
* Math::BigInt::Calc->_gcd(): Speed up by reducing amount of data copying
(Peter John Acklam).
* Add '01load.t' for basic module loading and diagnostics useful for
debugging. Rename '00-signature.t' to '00sig.t', 'pod.t' to '02pod.t', and
'pod_cov.t' to '03podcov.t' (Peter John Acklam).
* Math::BigInt:: Make from_hex(), from_oct(), and behave more like hex() and
oct() in the Perl core, and make from_bin() consistent with from_hex() and
from_oct() (this is related to RT #58954) (Peter John Acklam).
* Math::BigInt::Calc->_rem(): Modify first input arg always, not just
sometimes (Peter John Acklam).
* Math::BigInt::Calc->_modinv(): be more consistent with the _modinv() method
in other libraries (Math::BigInt::GMP, etc.) (Peter John Acklam)
* Math::BigInt::Calc->_nok(): use symmetry property nok(n,k) = nok(n,n-k).
This cuts computation time tremendously when n and k are large (Peter John
Acklam).
* Math::BigInt::Calc->_gcd(): quickly handle zero cases, avoid code
duplication, and always modify the first input argument in-place (Peter John
Acklam).
* Clean up code and add more code comments (Peter John Acklam).
* Fix typos (Peter John Acklam).
1.991 2011-02-05 pjacklam
* Add workaround for library inconsistencies (Math::BigInt::Calc vs.
Math::BigInt::GMP). This makes older versions of Math::BigInt::GMP
work with latest version of Math::BigInt (Peter John Acklam).
* Correct and extend API documentation (Peter John Acklam).
1.99_05 2011-01-29 pjacklam
* Fix typos (reminder -> remainder etc.) (Peter John Acklam)
* Fix Math::BigInt::Calc::_num returning NaN, not Inf, when it overflowed
(Peter John Acklam) (Closes: RT #25274).
* Fix Math::BigFloat->bcmp() so it can handle arbitrarily large exponents
(Peter John Acklam) (Closes: RT #62764).
* Fix bmodpow() in Math::BigInt 1.99 mis-calculating powers of one
(Peter John Acklam) (Closes: RT #63237).
* Fix bmodpow() and bmodinv() in Math::BigInt to handle negative input
(Peter John Acklam) (Closes: RT #61543)
* Clean up whitespace (Nicholas Clark).
* Added file t/00-signature.t for testing SIGNATURE (Peter John Acklam).
Complete version history of the rewrite project
===============================================
If you just want to see which things are new and different from the original
Math::* in the Perl core, see HISTORY.
##############################################################################
Math::BigInt::Calc:
0.52 2007-09-16 Tels
* fix 64bit ints on Perl v5.8.0 (thanx zefram)
0.51 2007-05-30 Tels
* use CORE::hex() instead of hex() to help bigint/bignum/bigrat
* use 9 digit parts on 64bit integer or long double systems
0.50 2007-05-05 Tels
* speed up _mul() by "use integer;"
* we do not need to remove zeros after mul()
* implement an alternative algorithm for _fac()
0.49 2007-04-16 Tels
* API version 2.0 support: add _1ex(), _alen()
* make _fac() about twice as fast
0.48 2007-01-27 Tels
* support for octal numbers
0.47 2005-05-17 Tels
* remove shortcut in div(), it wasn't working properly
0.46 2005-03-29 Tels
* avoid crash in FastCalc by making $BASE and $BASE_LEN use vars qw//;
0.45 2005-03-20 Tels
* fix the div() shortcut for short numbers to actually work
0.44 2005-01-01 Tels
* small cleanups
* shortcut for numbers of same length in _div, where X > Y
0.42 2004-10-10 Tels
* fix critical bug in _from_hex() with parts that were to big for one part
(introduced in v1.72, thanx Mark Lakata for finding it!)
0.41 2004-07-30 Tels
* from_hex() convert 28 bits (vs 16) at a time, faster (helps from_bin(), too)
* potential bug in padding with '0' in _digit()
* fixed undef warnings in fceil(0.222222222222...) (thanx kenny!)
* removed the unused integer-detection code and combined the two BEGIN blocks
0.40 2004-03-12 Tels
* added: api_version(), _ten(), _two(), _is_ten(), _is_two(), _gcd()
* streamlined: is_foo() methods
* _new() takes scalar, not scalar ref
* _str() returns scalar, not scalar ref
* _and(): bugfix for [perl #26559]: negative arguments that are shorter
than the positive one caused an error due to cutting instead padding
* _ior(): forgot to calculate the proper sing of result, making, for
instance, 30 | -4 go wrong
0.39 2004-01-25 Tels (not released)
* _zeros(0) is 0, not 1
0.38 2003-12-30 Tels
* guess _log_int() result based on $base if $base < $BASE
* _pow() handle cases 0 ** Y, 1 ** Y, X ** 0 and X ** 1
* _new(): shortcut for short numbers, makes MBI->new() about 20% faster
* _root() was wrong for numbers like 9 (0b1001) because they start with
the pattern /^0b1(0+)/ (missing '$' in regexp) and after fixing this
it was dead slow for large numbers.
0.37 2003-12-11 Tels
* implemented _log_int() with a simple and fast "iterative" method
* fixed bug in _root(): int() rounds sometimes wrong, so use sprintf()
* _as_bin() and _as_hex() are faster (for small values) due to inlining
is_zero()
* _acmp() is about 26% faster for very small numbers or numbers that
differ in length, and slightly faster for bigger numbers. This helps
both bacmp() and bcmp()
* _fac() did:
+ not modify $x in place for small arguments
+ something strange for large arguments
+ not handle 0..2 optimal (code now simplified)
* _as_bin() used %b, which was not known to v5.5.3 - workaround that
* implemented _log_int(), which is simple and very fast
* implemented the missing pieces for _root() (which is quite fast)
0.36 2003-08-31 Tels
* fixed a bug in div_use_div() that computed remainder wrong if X == X and
X was very large
* fixed a off-by-one error discovered with mbi_rand.t in _div_use_XXX()
(one internal in $x overflowed, thus the wrong computation)
0.35 2003-07-06 Tels
* fixed a bug in _floor() which caused ffloor(0.1234567) to fail.
(Thanx to cpan@ali.as for finding it and sending a fix/testcases)
* make _as_hex() and _as_bin() handle 0, and make them faster for very
short numbers (less than BASE_LEN digits)
0.34 2002-09-27 Tels
* fixed bug in mul_use_div() shortcut that used * $RBASE instead of / $MBASE
* $caught & 1 != 0 vs ($caught & 1) != 0 (changed to $caught != 2)
* $i %= $MBASE does not work on ARM (v5.003), so make it $i -= $car * $MBASE
* removed unused LEN_CONVERT code (smaller memory footprint)
0.33 2002-09-09 Tels
* _fac() keep $n as scalar if possible
* test for when to USE_MUL or not was inverted
* _mul() is about 6 times faster if $y is small and $x is big
0.32 2002-08-21 Tels
* fixed bug in _rsft() that did not set result to 0 in some cases
* _modinv() now works, thanx to the all-positive algorithm
* much more tests in bigintc.t (taken over from FastCalc)
0.31 2002-08-13 Tels
* _acmp() no longer calls _len() => tad faster
* some cleanup of old code, added some more comments
0.30 2002-06-10 Tels
* undef mul/div in case Calc.pm get's loaded twice
* fix in _as_hex() and _as_bin() for older Perls
* speedups in _pow() and _modpow()
0.29 2002-06-09 Tels
* filled in _modpow()
0.28 2002-05-30 Tels
* added _modinv(), _modpow() (not yet implemented)
0.26 2002-03-17 Tels
* a fix in _rsft() that left empty array instead of (0)
* a fix in _sub(): early out made -1 + 100000000001 == 0 (if length($y) > 8)
0.25 2002-03-03 Tels
* started _square() (not done yet)
0.24 2002-02-27 Tels
* streamlined _mod() shortcuts
* _div() has shortcut if $y is very small
0.23 2002-02-24 Tels
* from_bin() repack input and use from_hex(): twice as fast
0.22 2002-02-10 Tels
* _sqrt1() => _sqrt() (oups)
* much better guess for _sqrt() resulting in faster sqrt
* added _fac()
0.20 2002-01-07 Tels
* better detection of higher-int-only base (but disabled due to failures)
* streamlined converting
* turned dual-basis off by default (now 7-7 on 32 bit and 9-9 on most 64 it)
* _str() uses int() on first part to avoid '0000' instead of '0'
0.19 2001-12-23 Tels
* first working version of using two different bases: one for mul/div, the
other for all other ops, including converting via _to_large()/_to_small()
0.18 2001-12-20 Tels
* added _as_hex() and _as_bin() with 16 bit chunks
* from_bin() now uses oct() and 16 bits per iteration
* removed needless return statements
0.17 2001-12-06 Tels
* added _sqrt() for more speed
* _sqrt() shortcut for small (< $BASE) numbers for better performance
* shortcut in _mul for small numbers (< $BASE_LEN2)
* added _and, _or, and _xor and let them use more than 16 bits
* find out how many bits _and, _or and _xor can safely use (cap at 23)
* div() might leave empty array, so __strip_zeros fixes these
* streamlined _acmp()
* cap of 5 for BASE for UTS and UNICOS/Cray
* better test to find out what BASE should be (use +0.0 to force floats)
0.16 2001-11-19 Tels
* fixed comments a bit
* finished _mod() when $y < $BASE and $BASE % $y != 0 and $BASE % $y != 1
* streamlined _mod() loops a bit
* added _pow() for faster bpow()
* small fix to make 5.005_03 happy ($x = shift @prod vs $x = shift @prod || 0)
0.15 2001-11-11 Tels
* added _dec() and _inc() for much faster $x++ and $x--
0.14 2001-11-04 Tels
* added _mod() for faster $x % $y
0.13 2001-10-23 Tels
* better detection of BASELEN by matching against expected pattern
0.12 2001-10-03 Tels
* _div: 99999 => $BASE-1 ($MAX_VAL), that made some div's fail if $BASE != 5
0.11 2001-09-07 Tels
* automatically USE_MUL or USE_DIV
0.10 2001-08-24 Tels
* no longer export anything, ignore import calls
0.09 2001-07-20 Tels
* don't use warnings for older Perls
0.08 2001-07-15 Tels
* fixed bug in mul() shortcut
0.07 2001-07-15 Tels
* applied Philip Newtons spelling and doc patch(s)
* accidentally had the old, slow mul() code in. Oups.
* fixed also a bug in that new code
* also the speedup in mul() occurs with $x having lots of zeros, not $y.
* first argument is always classname, so removed checks and shift
* shift in base ten by _lsft() and _rsft()
0.06 2001-07-09 Tels
* first release
##############################################################################
Math::BigInt::CalcEmu:
0.04 2004-03-12 Tels
* removed unnec. emulation routines (all except _signed_foo)
0.03 2004-01-13 Tels
* $VERSION was overriding the $VERSION from MBI (Thanx Gisle Aas!)
0.02 2003-12-30 Tels
* the code in Calc::_root() uses now sprintf(), but the one in Emu was not
0.01 2003-12-26 Tels
* first version, taken over all the code from BigInt
##############################################################################
Math::BigInt::Scalar:
0.11 2002-01-07 Tels
* fixed version
* added DESCRIPTION section to stop pod2man complaining
* added _dec, _inc
0.10 2001-08-24 Tels
* no longer export anything, ignore import calls
0.06 2001-07-20 Tels
* don't use warnings for older Perls
0.05 2001-07-15 Tels
* first argument is always classname, so removed checks and shift
0.04 2001-07-09 Tels
* first release
##############################################################################
Math::BigFloat:
1.60 2008-04-20 Tels
* fix #34459: bsqrt() breaks on floats with enough digits (Thanx Niko Tyni!)
* fix #35238: batan2() handles inf/+inf wrong
* fix #35162: MBI segfault (as_number(Math::BigRat()) was wrong)
1.58 2007-06-30 Tels
* remove Exporer from @ISA
* support config('lib') as shortcut for config()->{lib}
* add bpi(), bcos(), bsin(), batan(), batan2() methods
* add bmuladd()
* streamline the is_xxx() and copy() methods
1.57 2007-05-05 Tels
* add bnok() method (n over k)
* add all the missing modify() hooks
1.55 2007-04-16 Tels
* make bexp() much faster (esp. under GMP) by caching the first coefficients
and rewriting the inner loop
* support "try" and "only" in import()
1.54 2007-04-09 Tels
* fix bug #21747: Re: weirdity in bignum... (powers and high precision):
infinite loops for blog() (and consequently bpow()) if you requested
an accuracy greater than 67 digits (uses _log() now, and not blog())
Thanx to darconc!
* cache the result of _log(2) and _log(10) so that subsequent calculations
can re-use the already done work
* instead of computing _log(10), compute _log(1.25) and _log(2) and then do:
_log(1.25 * 2 * 2 * 2) = _log(1.25) + _log(2) + _log(2) + _log(2)
This makes computing _log(10) much faster, so that computing blog(N) is
about a factor of 5 faster when N >= 10 or N <= 0.1
* add bexp()
1.53 2007-03-04 Tels
* fix #25144: [PATCH] Math::BigFloat->new considers any reference a BigInt
(Thanx mschwern!)
* fix bug #13866: NaN (in bignum queue)
* fix bug #21586: Incorrect result when comparing with NaN
* fix bug #15896: "==" overloading is broken for "NaN"
1.52 2007-01-27 Tels
* fix brsft() and bpow() in list context only return on number (bug #21413)
* make as_int() return a BigInt, too (not just as_number()) (bug #21412)
* add as_oct()
* bpow(): handle negative X and negative Y (instead of returning NaN)
1.51 2005-04-10 Tels
* fix new() to work with Math::BigInt::Pari
1.50 2005-03-29 Tels
* fix rounding doc, add notes about prevision vs. accuracy
* set FastCalc as default (we still use whatever MBI uses)
1.49 2005-03-20 Tels
* remove dependecy on Scalar::Util in bdiv()
* bdiv() cache result of "!$y->is_one()" for wantarray case to make
($res,$rem) = $x->bdiv($y); about 10% faster
1.48 2005-01-01 Tels
* use new interface to _scale_a() and _scale_p() in BigInt
* add bneg() and inline is_zero() in it, making it 1.6 times faster
* replace ref($_[0]) w/ undef when it isn't actually needed. This
makes some ops (bsstr(), bneg etc) about 2% faster for small numbers
* use MBI::_register_callback() to get notified of lib changes
* bgcd()/blcm() never worked, so fix them for integers and add tests
1.47 2004-10-10 Tels
* inf/NaN fixes for bpow()
* eliminate the need for _zeros() in new() (speed-up for GMP et. al.)
* eliminate _is_zero() in new() (small speed up)
* added shortcut for simple numbers in new() (speed up)
1.46 2004-08-13 Tels
* blog(10,10) ($x == $y) returned '1.0000...' instead of '1'
1.45 2004-07-30 Tels
* simple inherit bsub() from BigInt, also fixes bsub() failing under
$x -= $x - Thanx Peter J. Acklam!
* bdiv() failed when passed a variable twice (thanx Peter J. Acklam!)
* bfround() and bround() are about 10% faster when going via Math::BigInt's
bround() due to constructing a fake BigInt instead of going via ->new()
* fixed undef warnings in bpow(0,$y) ($y non-integer) (thanx kenny!)
1.44 2004-03-12 Tels
* bpow() computed -X ** Y wrong for Y that are odd
* use $HALF instead of 0.5 to speed up broot()
* use Calc instead of BigInt for parts, that makes it roughly 2x faster
it also saves memory (419 vs. 767 bytes per (small number) object)
* bmod() did needlessly test for NaN arguments twice
1.43 2004-01-13 Tels
* small fixes in AUTOLOAD
* delete $x->{_a} vs. $x->{_a} = undef to save memory
1.42 2003-12-30 Tels
* ffac(inf) is inf, not NaN
* flog() calculate integer result first, and if it fits, return it
this makes it much faster in case the result is a perfect integer
* require (instead of use) Exporter
* froot() calculates an integer result first, and it if fits, returns it
1.41 2003-12-11 Tels
* flog(): 0.5, 0.25, 0.125, 2, 4 and 8 were not scaled properly back to
1, instead they remained 0.5 and 2, respectively. This was a '<' vs.
'>=' respective '<' vs. '<=' issue. No other values are affected
(neither getting slower nor faster), but the ones in question (incl.
their multiples like 20, 80, 0.0125 etc) are now tremendously faster -
about a factor of 30 to 60! :-)
* removed some crufty logic from _log_10() and made the special cases of
2, 10 and 0.1 slightly faster. This also helps log($x,2) and log($x,10).
* bfac() slightly faster for small arguments
* downgrading to bigint failed for .2e2 (produced 200 vs. 20)
1.40 2003-09-23 Tels
* bstr(): removed unnec. BigInt math and inlined is_zero() => great speedup
(10% to factor 6.5 depending on input)
* replace $self->_one() by $self->bone()
1.39 2003-07-06 Tels
* $x->blog($base) can handle a $base which is a Math::Bigint
* replace die() with Carp::croak
1.39 2002-11-03 Tels
* $x->bpow($y,0), $x->blog($base,0) and $x->bdiv($y,0) were still not doing
the right thing and no tests caught it *sigh*
* blog():
+ MUCH faster when $x > 10 or $x < 0.1 (constant time vs.
time * 10 when doubling/halving $x)
+ also much faster if $x has many digits (like 1/3 or 123**123)
+ for $x < 1 and $x > 0 did not work at all (bacmp vs bcmp)
+ returns now NaN if $base <= 0 or $base == 1
+ does handle other bases than "undef" (aka e) properly now
* require Math::BigFloat did not work (opposed to BigInt, where it does)
* _pow() suffered the same bug of bacmp vs bcmp (so 0.2 ** 0.2 failed)
* removed unused _pow2() routine
* _find_round_parameters() returns ($x,$a,$p,$r) and not ($a,$p,$r), so
use it correctly, and also test for $x = NaN afterwards
(happens when $a and $p were set and thus $x became NaN)
* bsqrt() failed since v1.63 for values like 0.2, 0.002, 0.00134 etc
* added broot() method (albeit slow for now)
* $x->is_one('-') was broken (never returned true for $x == -1)
* config() can take arguments and set them, croak on wrong ones
* config(trap_nan => 1) to manipulate former $NaNOK variable
* config(trap_inf => 1), too
* trap_nan/trap_inf really croak on any attempt to create an NaN/inf
* spellings of Bigint => BigInt
* simplify config() by using SUPER::config()
1.38 2002-09-08 Tels
* fix that bsqrt() would hang for certain inputs. Instead of using Newton's,
we now rely on the fact that sqrt(x*y) = sqrt(x) * sqrt(y) by setting y to
100. This removes the while loop entirely and makes it much faster while
fixing the bug at the same time.
* $x->bsqrt(0) did needless warn about undef values, and round to 4 digits
instead of beeing equivalent to $x->bsqrt(undef)
* ditto for $x->bpow($y,0), $x->blog($base,0) and $x->bdiv($y,0)
* use File::Spec was needless, since it was required later on again
1.37 2002-08-20 Tels
* bcmp()/bacmp() upgrade now if requested
1.36 2002-08-13 Tels
* as_hex() and as_bin() work now at least for inf, NaN and integers
* fixed bsstr() (and thus also numify()) for negative numbers - Ouch!
* $x->new("0.02"); $x->accuracy($a); $x->bdiv($y,$d) failed to round
when $d > $a
* numify() returned '+inf' instead of 'inf'
* (more) tests for bsstr(), numify(), as_hex(), as_bin
1.35 2002-07-07 Tels
* bfround() used accidentally BigInt math; is now about 5.6 times faster for
small numbers
* bdiv()/badd() etc skip objectify() if possible and are thus faster
* doc for accuracy()/precision()
* $x->bmod() was not modifying $x in place when returning NaN/inf/-inf
* avoid unec. calls to objectify() for binary op's
1.34 2002-06-10 Tels
* upgrade used badd() instead of bmul() inside bmul() (again! arg!)
1.33 2002-06-09 Tels
* import() fixed for older Perls
1.32 2002-05-19 Tels
* upgrade used badd() instead of bmul() inside bmul()
* bpow() now uses slower, but more correct way for fractions (this needs work)
1.31 2002-03-03 Tels
* bpow() can handle second arguments beeing non-integer (f.i. 2 ** 0.2)
* $x->bpow(0.5) optimized to $x->bsqrt();
1.30 2002-02-25 Tels
* bug in bsub() with not rounding when $x->bsub(0) was also in MBF
* bcmp() and bacmp() 5 times faster due to numify() (might have now impose a
limit on exponent - but I couldn't find a test that breaks it)
* streamlined ffloor() and fceil()
* fixed bug in $x->bsub(0) and $x->badd(0) (both forgot to round result)
* new() downgrade integers if $downgrade is in effect
* optimized fpow() (one is_zero() less)
* optimized as_number (nearly twice as fast)
* $x->badd(0) forgot to round $x
* downgrade and upgrade are valid methods for inheritance
1.29 2002-02-24 Tels
* overload for 'log' now inherited by BigInt
* _binf(), _bnan(), _bone() and _bzero() instead of longer bone() etc
* inf/NaN fixes from v1.51 were missing for BigFloat
* bdiv() upgrades if applicable
1.28 2002-02-16 Tels
* fixed use Math::BigFloat ':constant';
* fixed flog() function to calc right result, honour rounding-globals
1.27 2002-02-10 Tels (forgot to increase version)
* ffac()
* various: disable Math::BigInt::upgrade to avoid deep recursion
1.27 2002-01-06 Tels
* overload for log() and flog()/blog()
* bzero()/bone() handling of A & P was broken
* bround()/bfround() handling of zeros forgot to set A & P
* fdiv: fixed a bug in round to A with given round_mode (always used global)
* fsqrt(): would hang/fail if either $x's or global A or P were set
* fsqrt() didn't modify $x sometimes, but returned a new reference
* fsqrt(): calc 4 more digits for rounding, not 1 (endless looping otherwise)
* fmod() now actually works
1.26 2001-12-06 Tels
* fneg() failed (now hand up to MBI)
* frsft() and flsft() were no aliases to brsft() and blsft()
* fone() was no alias for bone()
* blsft() and brsft() were missing altogether
* streamlined: fpow() and fmul()
* removed the EXPORT_OK
* fqsrt() uses now BigInt::bsqrt() as guess: greatly improved performance
* make fsqrt() subclass proof by using $self instead of Math::BigFloat
* bzero(), bone(): take additional A and P and store 'em
* bnan(), binf(): clear A and P
1.25 2001-11-18 Tels
* streamlining fixes in new() were missing
* further streamlining in new() for 12345e1234 cases (fraction part empty)
* added $rnd_mode support for compatibility
* replaced the 'laber schwad blah blah' pod section by a pointer to MBI
1.24 2001-11-11 Tels
* bacmp() fix for +-inf
* streamlined new()
* faster finc()/fdec()
1.23 2001-10-05 Tels
* fixed facmp() (was broken the same way as fcmp())
* more rounding fixes from John P.
1.22 2001-10-03 Tels
* Quite a lot of rounding fixes
* $x->bnorm() is 4 times faster if $x == 0
* $x->bround($n) is 43 times faster if $n > $x->{_a} (no-op)
* added as_number()
1.21 2001-09-03 Tels
* serious bug in bcmp() caused 1.5 to be greater than 2. Yikes!
* bcmp() did not only return -1,0,1 and undef but other values, too
* new('inf') produced NaN (was expecting '+inf')
* exponent(), mantissa() & parts() failed or returned scalars for inf,-inf,NaN
* include finf in AUTOLOAD list
1.20 2001-08-03 Tels
* streamlined bcmp
* drop leading '+' for inf
1.19 2001-08-02 Tels
* 123/+-inf => 0, test for that and -1,0 / NaN => NaN
* +123 / 0 => +inf, -123 / 0 => -inf (was missing in MBF)
* fixed +-inf handling in bacmp/bcmp/bsub/badd/bdiv and tests for that
* padd bstr() output of numbers with set A or P
* remove bfloat() (Math::BigInt->bfloat() did not work, anyway, see bint())
1.17 2001-07-15 Tels
* applied Philip Newtons spelling and doc patch(s)
* added bone()
* tests for bnan() and bone()
1.16 2001-07-09 Tels
* is_positive(), is_negative()
* various pod fixes (overlong =item, spelling erorrs etc)
* removed internal _set() and the tests for it
* infinity support for fcmp(), fpow()
* nailed the bug in fdiv() that caused fsqrt() to fail. fsqr() works now, too.
* more tests
1.15 2001-06-15 Tels
* added bfloor(), bceil()
1.14 2001-06-13 Tels
* accuracy/precision rounding after fdiv() was missing
* binary integer input (0b01110 etc)
* A/P rounding after fdiv() was missing
* '-0x0' would wrongly leave '-0'
* as_number() was wrong for negative numbers and had no tests
* added is_even(), is_odd(), _set(), the inherited ones were broken
* fixed is_zero() for NaN
* $x->bpow($y) for negative $y was unfinished
* added is_inf(), binf() and some support for +-inf in new(), bsstr() etc
* added tests for is_odd(), is_even(), _set() and is_zero(), is_inf(), bsstr()
1.13 2001-06-09 Tels:
* adjusted fdiv() so that it now works proper with old testcases
* (except a few nits, see testsuite and ACCURACY)
* fdiv() in listmode (uses non-working fmod())
* fixed/test A/P after each op
* $x->accuracy(), $x->precision() actually round $x to the value A/P
* fixed fpow(), added tests for it
* hexadecimal integer input (0xdeadbeef)
* is_one() for -1 was wrongly true, tests for is_one()
1.12 2001-05-11 Tels
* taken over testsuite from John P.
* added tests for compare with fraction
* fixed fcmp/fround/ffround
* added accuracy/precision/fallback/round_mode
* bsstr('NaN') returned 'NaNeNaN'
1.11 2001-05-09
* bug bcmp() (1e-08 was < 0, aka fractions were broken)
1.10 2001-05-07
* Tom's round fixes (minus one nit)
* new: .xxx, -.xxx, +.xxx etc are valid inputs, while '.', 'x x x' and 'Exxx'
are now invalid
* finally got rid of C&P of overload section and clone()
1.09 2001-04-23
* length() in list context return length of mantissa & exponent
* bug in bstr() for '0.x' style strings
* added bsqrt()
* workaround for Perl v5.6.0 overload-bool bug (via MBI)
* fixed rounding
1.08 2001-04-18
* exponent(), mantissa() and parts() now return BigInt's
* bnorm: 0Ey => 0E1 (was wrongly 0E0)
* fixed is_zero()
* added bround() and bfround() (only truncate mode)
* fixed bug in bstr() for 1.203E-2 style numbers (Thanx Tom!)
1.07 2001-04-07
* bug in bstr() for 0.xxx style numbers, as well as for "-xxx"
* babs(), bneg(), bint() work now
* empty stubs for bsqrt(), bround() and bmod()
* exponent(), mantissa(), parts() work now as expected
1.06 2001-04-05
* bstr() returns NaN for NaN's
* renamed _norm to bnorm, added it to AUTOLOAD for compatibility
* fixed bug Math::BigFloat->new(Math::BigInt->new(3));
* bug mul/div when second arg was BigInt
* bdiv() works now with precision
* precision()
* doc about mixing different objects in overloaded math
1.05 2001-03-31
* fixed bstr() and bsstr()
* added AUTOLOAD for fxxx() to work as well as bxxx()
* enhanced and fixed testsuite for mul/cmp/add/new
1.04 2001-03-27
* bmul/bdiv/cmp work now, better _norm()
1.03 2001-03-06
* layed more foundations (mul() etc)
1.02 2001-02-24
* add()/sub() should work now
1.01 2001-02-22
* new() and bstr() work now (sort of)
1.00 2001-02-18
* started work
##############################################################################
Math::BigInt:
1.99 2010-11-15 rafl
* Stop as_int/as_number from losing precision (Peter John Acklam)
(Closes: RT#43694)
* Fix Math::BigInt::Calc::_modpow for (0 ** $x) % $y, with $x > 0
(Peter John Acklam) (Closes: RT#62918).
* Stop $x -> bmodpow(1, 1) from failing when $x is large (Peter John Acklam)
(Closes: RT#62949).
1.98 2010-11-08 rafl
* Fix from_bin() documentation error (Peter John Acklam) (Closes: RT#61845).
* Make as_int($inf) return inf, not NaN (Peter John Acklam) (Closes RT#62101).
* Fix various typos in documentation and tests (Peter John Acklam)
(Closes RT#62643).
* Make digit($n) return 0 for "out of range"-digits (Peter John Acklam)
(Closes RT#61812).
1.97 2010-11-07 rafl
* Reorder the list return of Math::BigInt::Calc::_base_len() (Nicholas Clark)
This change requires an update of Math::BigInt::FastCalc to version 0.24.
* Fix segfault when upgrading irrational numbers (Father Chrysostomos)
1.96 2010-09-28 rafl
* Various documentation fixes provided by gregor herrmann
1.95 2010-09-14 rafl
* Re-upload v1.94 as a stable release
1.94 2010-09-13 rafl DEVELOPMENT RELEASE
* Attempt to fix Math::BigInt::Lite failures
1.93 2010-09-13 rafl
* Depend on perl >= 5.6.2
* Remove obsolete core test directory boilerplate
* Convert from Test to Test::More
1.92 2010-09-10 rafl
* re-upload v1.91 with a fixed SIGNATURE
1.91 2010-09-10 rafl
* fix various documentation bugs
1.90 2010-09-03 rafl
* fix bnok() for k==0 and k==n-1
1.89 2008-04-20 Tels
* fix #35238: batan2() handles inf/+inf wrong
1.88 2007-09-22 Tels
* fix wide ints on Perl v5.8.0 (Thanx zefram!)
* minimum required is Perl v5.6 (tested by zefram)
* _find_round_parameters(), _scale_a() and _scale_p(): trunc A/P to integers
* fix from_oct(), from_bin() and from_hex()
1.87 2007-06-30 Tels
* fix undef base in blog()
* support config('lib') as shortcut for config()->{lib}
* _find_round_parameters(): convert $a & $p to normal scalars, or bad
things will happen during rounding of BigFloats
* add bpi(), bcos(), bsin(), batan(), batan2() methods
* add bmuladd()
* streamline the is_xxx() and copy() methods
1.86 2007-05-05 Tels
* bump version
1.85 2007-05-05 Tels
* bump version
1.84 2007-05-04 Tels
* add bnok() method (n over k)
1.83 2007-04-16 Tels
* bump version
1.82 2007-04-09 Tels
* use $CALC->_zeros() directly (instead _trailing_zeros()) to speed up
exponent() and mantissa()
* fix documentation that blsft() and brsft() default to base 2 (not 10)
* add bexp() and fix overloading for exp()
1.81 2007-03-16 Tels
* no code change, just a package update
1.80 2007-03-04 Tels
* require Perl v5.6.2 as minimum
* fix bug #24969 (Can't use an undefined value as an ARRAY reference)
* fix bug #12857: Subclasses and overload
* fix bug #13866: NaN (in bignum queue)
* fix bug #21586: Incorrect result when comparing with NaN
* fix bug #15896: "==" overloading is broken for "NaN"
1.79 2007-02-02 Tels
* fix typos
1.78 2007-01-27 Tels
* implement "try" and "only" as replacements for "lib"
* make 'use Math::BigInt lib => "foo"' warn if foo cannot be loaded and a
fallback occurs
* fix bug #21446 - Docs/code inconsistency for bnorm() method
* fix bug #21964 - A patch to include a rounding mode of 'common'
* fix bug #21445 - Documentation error for exponent() method
* fix bug perl #41050 - NaN returned when raising integer value to negative
power
* add from_hex(), from_oct(), and from_bin()
* add as_oct()
1.77 2005-05-17 Tels
* bump version
1.76 2005-04-10 Tels
* fix rounding doc, add notes about prevision vs. accuracy
* trap inf and -inf in new()
* load FastCalc as default
1.75 2005-03-20 Tels
* use a trick to remove the dependency on Scalar::Util in bsub()
* fix atan2(), it did not preserve the order of arguments
(Thanx to Ambros & Zaxo for report and patch!)
1.74 2005-01-01 Tels
* streamline _scale_a() and _scale_p() for more speed in rounding
* remove the now unnec. support for MB_NEVER_ROUND and {_f}, this
makes all ops that call round() a tad faster (one exists is
removed) and shrinks the codesize a bit
* streamline bneg(), inline is_zero(): makes it 1.6 times faster
* replace ref($_[0]) w/ undef when it isn't actually needed. This
makes some ops (bsstr(), bneg etc) about 2% faster for small numbers
* restrict low-level math library names to sane chars to avoid
exploitation of eval()
* fill_can_cache() accidentally did checks for 'or' & 'xor'
* inline _fill_can_cache
* add _register_callback() to notify subclasses of lower math lib changes
* bgcd() is now about 10% faster
* is_positive(0) == 0, since 0 is neither positive nor negative
* streamline bmod() a bit
* fix blog() constructing arguments (broke Math::BigInt::Constant)
1.73 2004-10-10 Tels
* overloading of <<= and >>= makes these ops about 10% faster and fixes the
problem that "$a <<= 2" would create a different object for $a to point to
* quite a lot of fixes for NaN/inf handling in bpow() (bmul already did it
right) - bug report by jeff at thekidders com and Hugo - Thank you!
1.72 2004-07-13 Tels
* no changes
1.71 2004-07-08 Tels
* fixed bsub() failing under $x -= $x; Thanx Peter J. Acklam!
* _scan_for_nonzero() reuses length/stringform of $x and is thus faster, this
helps rounding if the number after the roundposition is '5'
1.70 2004-03-12 Tels
* bpow() computed -X ** Y wrong for Y that are odd
* 0 ** -Y => +inf (was NaN) due to 0 ** -Y => 1/0**Y => 1/0 => +inf
* fixed bug in perl -Mbignum -le 'print 2 ** 46 * 3' under Bigint::Lite
leading to "Can't use an undefined value as an ARRAY reference at
/usr/local/lib/perl5/5.8.2/Math/BigInt/Calc.pm line 462."
* fixed upgrading of blog() with base = undef (means: base e)
* make the synopsis actually runnable (Thanx Paul McCarthy)
* blcm(): handle a list of strings (instead one obj and some strings), too
1.69 2004-01-13 Tels
* bacmp(+-$x,-inf) was wrong (Thanx William T. Morgan!)
* digit($x,$y) segfaulted under 5.6.1 if $y was a BigInt
* blog() was missing the modify() check (breaking MBI::Constant)
* delete $x->{_a} vs. $x->{_a} = undef to save memory
1.68 2003-12-26 Tels
* bfac(inf) is inf, not NaN
* added alias names: as_int() (as_number()), is_pos(), is_neg() and doc
* factored out all the emulation code and moved it to Math::BigInt::CalcEmu
* binary/hexadecimal input was twice as slow as v1.66 due to a typo in v1.67
* streamlined overload for boolean context (20% faster "... if $x;")
* round() was missing a croak() in path testing for wrong roundmode
* badd(): optimize away setting of sign if it is already right
* bdec() is about 10% faster for negative numbers
* bpow(): removed some now needless tests for 0 and 1: about 30% faster
for small numbers
* streamlined exponent() (parts() benefits from this, too)
1.67 2003-12-02 Tels
* overload for cos/sin/exp/atan2 to make cos(Math::BigInt->new(...)) work
* implemented blog() with a simple and fast "iterative" method
* use _log_int() in $CALC if possible
* cache $CALC->can(...) calls in global %CAN hash for speed
* reorder is_zero() check for band(), bior() and bxor() to speed up the
case for when the underlying lib has _and(), _ior() and _xor()
* implement a new way of emulating AND, OR and XOR, this tremendously
helps if band() et. al. are called with negative arguments
* try to call _signed_or(), _signed_and() and _signed_xor() in lib
* is_foobar() methods are slightly faster
* bnot() is about 12% faster
* bsqrt(): moved is_zero() || is_one() test out of the way => 28% faster
for "small" values (Calc and GMP)
* small change for overload::constant
* bfac(): do 0 or 1 check only if CALC cannot do _fac() (thus faster)
* removed a needless _copy in bmod() with negative arguments (slightly faster)
1.66 2003-09-01 Tels
* document accepted inputs better
* fix wrong upgrade and undef-parameter handling in broot()
* implement broot() if lib doesn't have a _root() routine for $y that are
powers of two and for small $x
* warn if broot() cannot yet compute proper result
* remove needless _one(): 3% speedup for binc()
* remove needless _swap(): 1% (Calc) - 6% (GMP) speedup for overloaded math
1.65 2003-07-13 Tels
* document that config() can set certain values
* replace die() with Carp::croak()
* remove needless is_zero() check in as_bin() and as_hex(), making them
faster, especially when under a different lib like GMP.
* Fixed the infinite recursion in bignum. See http://xrl.us/k6y
* fix handling of 0e999, 0e-999 etc
1.64 2002-11-03 Tels
* removed needless "my $c = ...;" statements in binf() and bnan()
* forgot () around "$x->{_f} & MB_NEVER_ROUND"
* bsqrt(inf) == inf, not NaN
* $x->bdiv($x) did not round the resulting 1 properly
* removed the shortcut testcode in bdiv() (Calc handles this now)
* added (non-working for now) broot() method
* changed length() to CORE::length() in two places (thanx Liz!)
* config() can take arguments and set them, croak on wrong ones
* config(trap_nan => 1) to manipulate former $NaNOK variable
* config(trap_inf => 1), too
* trap_nan/trap_inf really croak on any attempt to create an NaN/inf
* spellings of Bigint => BigInt
* _find_rounding_parameters(): set $a to undef if it is 0
1.63 2002-09-08 Tels
* bsqrt() did not modify $x but returned new object when lib does not have
a _sqrt() routine (BareCalc, BitVect and Pari are affected, Calc, FastCalc
and GMP were not)
1.62 2002-08-21 Tels
* bcmp()/bacmp() upgrade now if requested
* bmodinv() uses an all-positive algorithm, speeding it up by about 5-8%
and allowing to implement the same algorithm in Calc for factor 4 speedup
1.61 2002-08-13 Tels
* tests for bsstr()/numify() with negative/special inputs
* bround() keeps $scale as scalar for speed and less problems
* fix for trailing newlines in input
* some doc fixes (especially return values of is_foo() methods)
* make testsuite so that it will pass under FastCalc easily
1.60 2002-07-07 Tels
* shortcuts to avoid calls to objectify for add/sub/mul/div/mod/pow/bcmp etc
* fix overloaded bcmp() so that the objectify()-avoidance kicks in
* avoid calling round() when BigFloat requested 'no rounding please'
* bcmp()'s shortcut for comparing x <=> 0, 0 <=> 0, 0 <=> $y was making things
slower than just handing the compare to Calc. Even more so for Pari et al.
* $x->accuracy() and $x->precision() returned undef, instead of 0 if
A/P of $x was 0 and global A/P was undef.
* $x->bmod() did not modify $x in place when returning NaN/inf/-inf
* some binary ops (band/bxor/bior/bpow) were not properly rounding the result
to the requested A/P/R; the same ops also forgot to take $y into account
* doc for accuracy()/precision()
1.59 2002-06-10 Tels
* pod fixes for bmodpow()/bmodinv()
* fix in as_hex() and as_bin() for older Perls
* speedups in bpow(), bmodin() and bmodpow()
1.58 2002-06-09 Tels
* invalid inputs with two dot's (1.2.3 or 1..2 etc) are now really invalid
1.57 2002-05-30 Tels
* fixed objectify() to make "perl -Mbigrat -le 'print 1+2/3'" work
* added bmodpow() and bmodinv() as (not-working yet) stubs
1.56 2002-03-17 Tels
* documented config()
* simplified import() logic a bit
* changed some isa->($upgrade) => !$isa->($self);
1.55 2002-03-17 Tels
* :constant picks up binary/hexadecimal constants
* Math::BigInt->digit(123) works now
1.54 2002-03-03 Tels
* really fixed overlong pod =item
* downgrade() and upgrade() with undef as argument didn't clear the variable
* bmul() upgrades if second argument is non-integer
* bdiv() upgrades if $x > $y
* bpow() upgrades if second argument is non-integer
* objectify disable downgrade (for MBF)
* new() twice as fast due to shortcut simple numbers, save _split() & _round()
1.53 2002-02-27 Tels
* precisision typo
* fixed overlong pod =item
* added downgrade()
1.52 2002-02-24 Tels
* hooks for _bin(), _bnan(), _bone() and _bzero()
* =head2 section for accuracy
1.51 2002-02-16 Tels
* fixed bfround(-x) (f.i. 0.004->bfround(-2) resulted in 0.01, not 0.00)
* bfround(x) rounded at wrong place (off by one)
* calling bfround(x) rounded further and further instead of keeping result
* blog() upgrades if requested
* added doc stub for every public function
1.50 2002-02-10 Tels
* bfac() and hook for _fac() in libs
* documented sub-classing and auto-upgrade
* < 4 test in bsqrt() after the CALC call for more performance
* added overload for sqrt()
* added possibility to upgrade via use Math::BigInt upgrade => 'Foo::Bar'
* Math::Big(Int|Float)->accuracy() clears precision, and vice versa
* small optimization in bdiv() regarding abs($x) < abs($y)
* brsft() for negative numbers in base 2 was completely wrong
1.49 2002-01-07 Tels
* as_hex() and as_bin() use 16 instead of 8 bits per iteration
* overload for log() and blog()
* tricks to make 'require Math::BigInt' and 'use Math::BigInt();' work again
* use $CALC instead of require for newer Perls (test for $] > 5.006 vs 5.6)
* bzero()/bone() handling of A & P was broken
* bround()/bfround() forgot to set A or P for zeros
* embedded _find_round_parameters into round(), streamlined both versions
* round() now uses string-add to make it almost twice as fast
* bnot() did round twice
1.48 2001-12-06 Tels
* fixed pod in many places
* bmod: use round(), not bround()
* bsqrt: use _sqrt() from lib, if possible
* bsqrt: would hang for certain (most?) inputs
* bdiv: slow check for 1 || -1 replaced by much faster version
* bdiv: call _div() only when nec. in list context, otherwise scalar
* streamlined copy(), _find_round_parameters()
* removed the EXPORT_OK except for objectify, _swap and bgcd/blcm
* bzero(), bone(): take additional A and P and store 'em
* bnan(), binf(): clear A and P
1.47 2001-11-18 Tels
* added $rnd_mode support for compatibility
* two 'my $t = ... if ..;' cases to 'my $t; $t = ... if ...;'
* added overload for %=, |=, &= and ^= for more speed
* _split(): check for 1e2e3 and reject it
1.46 2001-11-11 Tels
* binc(),bdec() use lib (via _inc(),_dec()) => faster (see BENCHMARK)
* avoid the unnec. rounding bsub()/binc()/bdec() (badd() already took care)
* made bsub() faster by removing the bneg() overhead from it
1.45 2001-11-04 Tels
* tests run now in subclass, too
* bmod() can use _mod in lib
* lots of tests fixed (assumed wrong base etc) and added
* bpow() about 10-15% faster for small numbers (like 2 ** 150, 3 * 200 etc)
1.43 2001-10-05 Tels
* $x->bround($n) is 43 times faster if $n > $x->{_a} (no-op)
* Heaploads of rounding fixes (and tests)
* Test for 99999-bug in Calc
1.42 2001-09-03 Tels
* bug in overload section causing performance losses in subclasses
* call $CALC->import() with list of libs
* odd numbers never have trailing zeros, so don't convert them to DEC to look
* as_hex() and as_bin()
* $x->bmod() did not modify $x, only returned result. Oups.
* new('inf') produced NaN (was expecting '+inf')
* exponent(), mantissa() & parts() failed or returned scalars for inf,-inf,NaN
1.41 2001-08-08 Tels
* fixed inf test (coredumps)
1.40 2001-08-03 Tels
* bxor(-$x,-$y) was broken (and not tested *sigh*)
* streamlined bcmp
* drop leading '+' for inf
* bxor(), band(), bior() with negative arguments don't get passed to lib
(makes it work with BitVect, Pari, GMP etc)
1.39 2001-08-02 Tels
* fixed history (duh!)
* assign return values from $CALC back to $x->{value}
* fixed +-inf handling in a lot of places and tests for that
* band(), bxor() and bior() now work with negative inputs
* remove bint() (Math::BigFloat->bint() just DNDWIM and no sense, either)
1.38 2001-07-15 Tels
* test for mul() shortcut
1.37 2001-07-15 Tels
* applied Philip Newtons spelling and doc patch(s)
* Benjamin Trott: _split() is faster for numbers that need no splitting
* Benjamin Trott: don't take shortcut in badd(), or Pari won't work
* allow use Math::BigInt lib => 'Pari,BitVect,Foo,Bar';
* delegate shifting to CALC if possible, otherwise fallback
* test for self-pow, to see if lib's fail (since BitVect failed for self-pow)
* _one() => bone()
* +x / 0 => +inf, -x / 0 => -inf, while 0/0 and +-x % 0 are still NaN
* tests for bnan() and bone()
* Math::BigInt::Calc now determines biggest $BASE to use. Default should now
be 1e7 on most systems, giving 20% to 40% speedups.
1.36 2001-07-04 Tels
* is_positive(), is_negative()
* various pod fixes (overlong =item, spelling erorrs etc)
* torn out the bones from under the flesh and moved them to Math::BigInt::Calc
* added Math::BigInt::Calc, Math::BigInt::Small (and Math::BigInt::BitVect)
* fixed tests for bacmp() (could never fail)
* removed internal _set() and tests for it
* +-inf handling in bcmp(), bpow()
1.35 2001-06-15 Tels
* added bfloor(), bceil()
* fixed bior(), bxor(), band() for $x->bxxx(NaN,0), added modify() to them
1.34 2001-06-13 Tels
* binary integer input (0b01110 etc)
* fixed: '-0x0' left '-0'
* added is_inf(), binf() and some support for +-inf in new(), bsstr() etc
* added tests for is_odd(), is_even(), _set() and is_zero(), is_inf(), bsstr()
1.33 2001-06-09 Tels
* bround() no longer uses 10 ** $pad and is thus much faster when rounding up
* fixed and added rounding benchmark (did time bmul instead bround)
* blsft(),brsft(): can work in different bases, check against invalid
inputs, more tests, speedup when in base 10
* _trailing_zeros is 50% faster
* A/P after each op, tests for it in accuracy.t
* round() instead of bnorm()
* $x->accuracy(), $x->precision() actually round $x to the set value
* tests for is_one()
* hexadecimal integer input (0xcafebabe etc)
1.32 2001-05-11 Tels
* added accuracy/precision/fallback/round_mode
1.31 2001-05-08 Tels
* _ between digits now accepted, ' ' no longer valid inside (but at front/end)
* Exxx is NaN, and no longer produces warning
* .xxx style numbers are valid input
* tests for 1E1, 123E-2, 1E2 etc style input to Bigint.pm
* fixed overload (w/ _swap/copy), subclasses can inherit it easily
* removed clone()
* added bsstr()
1.3 2001-04-23 Tels
* added (compatible to MBF) mantissa(), exponent() & parts() as well as tests
* _trailing_zeros()
* fixed as_number() to return copy of BigInt
* added bround(), bfround() and support for round_mode() as well as $rnd_mode
* fixed bug in bdiv() wich left reminder "-0", causing further op's to die()
* added is_valid to testsuite to see whether invalid objects are created
* added bsqrt()
* workaround coredump bug in bool() for v5.6.1
1.23 2001-04-07 Tels
* spelling errors in pod
1.22 2001-04-05 Tels
* documented Peters OS/390 patch/changes (fix was in for quite some time)
* fixed bug Math::BigInt->new(Math::BigFloat->new(3));
* objectify() with other objects than BigInt as further args, copy() etc
* $x->digit($n) to query fast value of Nth digit
* as_number()
1.21 2001-03-30 Tels
* bool() works now under 5_005
* bug in bsub where numbers with at least 6 trailing digits after any op failed
1.20 2001-03-24 Tels
* added: is_nan()
* bug in bmod/bdiv, I forgot some cases with negatives. Thanx to Bruce Fields!
* documented ':constant' and eval() crash on Perl 5.00x
* documented BigInts behaviour of bmod/bdiv and use integer
1.16 2001-03-09 Tels
* Math::BigInt::badd(4,5) and Math::SomeChildOfBI->badd(4,5) work now
* '$x = scalar (**|%|+|-|*|\) $object;' failed (was not tested, either)
* 'if ($x)' is now O(1) instead of O(N) and at least twice as fast
* fixed nasty bug in _digits that caused <=> after add/sub/mul etc to fail
if result was between 100001 and 109999, added test for this
* added test cases for op's that should preserve args (+,+=,abs(), neg() etc)
* added tests for overloaded 'bool'
* added test.pl and some examples (prime.pl, bigprimes.pl)
* tests after "use Math::BigInt :constant" were screwed due to not using eval
* $x->numify() (for $array[$x] = 0; etc) is much faster now
* added caveat documentation for $x = -$x; and $x *= string1 operator string2;
1.15 2001-02-24 Tels
* $x / $x is now a lot faster (more O(1) than O(N))
* 10 ** $x is now a lot faster (more O(N/5) instead of O(N))
* overload of **= makes $x **= $y faster
* 0 ** 0 was NaN, not 1
* -a % b = +c (was -c) to be compatible with perl
* added $x->length() and test for it; fixed _digits() (was off by 1)
* objectify() was not exported, added tests for objectify()
1.14 2001-02-21 Tels
* overload +=, -=, *= and /= for about 20-30% more speed if both args have
roughly same length
* shortcut in add() makes $x += $y; $x -= $y; for large $x and small $y
an O(1) case instead of O(N)
* fixed (non-critical) bug that caused objectify in numify/bool/stringify to
create scratch objects from undef params.
1.13 2001-02-18 Tels
* got rid of duplicated copy() code in new()
1.12 2001-02-16 Tels
* accidentally dropped self-multiply test in bigintpm.t
* fixed bug in overloading cmp
* after correcting the overload for 'cmp', I got a lot of test failings and
finally discovered that the bstr()'s return of '[+-][0-9]+' instead of
Perls ways of '[-]?[0-9]+' breaks string comparisons with numbers :(
F.i. ok() from Test.pm uses 'eq' and you can not do ok($a,3*3) where $a
is a BigInt. IMNSHO clearly wrong. And only changing the way cmp is
overloaded would lead to the curios situation that the following:
'print "$a eq $b" if $a eq $b;' would print "+3 eq 3", which looks wrong.
Mark B. said go ahead and change bstr(), so I changed it ;) to drop
the '+', adapted all the tests, changed the doc, etc.
BigInts behave now transparently like build-in scalars in integer/string
context ;o)
1.11 2001-02-14 Tels (first release)
* fixed bug in band(), bxor(), etc that used badd($x, fixed_number_here);
* since subclasses might not be happy with fixed numbers, make sure we pass
BigInts all the time if using something like $someclass->badd();
* fixed bug in band/bxor/bior which destroyed second argument
* bxor/band/bior work now correctly for subclasses
* ++ and -- are now a tad (ca 5%) faster
1.10 2000-11-24 Tels
* finally made it Math::BigInt (w/o trailing 's')
1.09 2000-11-23 Tels
* fixed bug in bmul (and thus bpow) (self multiply works now)
1.08 2000-11-22 Tels
* fixed all but one test (band bior bxor etc)
1.07 2000-11-20 Tels
* objectify fixed to not make copies and work with subclasses
1.06 2000-11-19 Tels
* 7 tests remain
* bgcd accepts lists, added blcm
1.05 2000-11-16 Tels
* 8 tests remain
* new copies _all_ fields, not only Math::Bigint ones
1.04 2000-11-15 Tels
* fixed bigintpm to test '++' and '--' properly
* done div, fixed mul/bpow (13 tests remain)
1.03 2000-11-14 Tels
* x**0 => 1 (instead of x)
* fixed bigintpm to include bpow, binc, bdec, new() test
1.02 2000-11-13 Tels
* fixed sub and mul (sort of)
* found out that "$wanted = shift || return bzero()" causes a call to numify,
* testing for undefined fixes this problem (but might waste more time for
* a new(0), will save time on average.
Math-BigInt-1.999829/CREDITS0000644403072340010010000000343514156375567015051 0ustar OSPJADomain UsersI wish to thank the following people:
* Mark A. Biggar and Ilya for the original versions.
* Steffen Beyer for the discussions and ideas, and for Bit::Vector.
* Bruce Fields for spotting bugs.
* Mark Dickinson for spotting bugs.
* HH for listening to my boring explanations.
* Peter Prymmer for spotting the OS/390 problems with / 1e5
* Tom Phoenix for the discussions about factoring/primes/speed.
* John Peacock for pushing me to finish Math::BigInt::Calc.
* Benjamin Trott for the _split optimization and finding the bug in badd()
* Daniel Pfeiffer for v0.49
* Compaq for their TestDrive accounts and the admins managing them - this makes
testing on a large variety of platforms possible. Thanx!
* Sisyphus for the discussions and ideas
* Jarkko for the inf/NaN help and for beeing generally helpful and witty
* Creager, Robert S for pointing me towards the precision/accuracy bug and for
general asking questions and providing feedback
* Feztaa for the report that let to the discovery of the _rsft() bug in v1.61
He also deserves the mention as the first known user of bignum :)
* Tim Rushing for reporting the bsqrt() hang and giving me the chance to
improve BigInt/BigFloat.
* cpan@ali.as for reporting the floor() bug with 0.1412024 and providing a
fix and testcase - thanx!
* Stephen Ross for finding the -2 ** Y with odd Y bug
Special thanx must go to John Peacock and Tom Roche, both have helped me a lot
in developing the latest version, not only by cheerfully kicking my lazy butt
from time to time, but also by providing advice, bug-reports, suggestions and
nagging questions, as well as bearing with my countless ranting emails. So,
thank you very much!
Also I want to thank all the ever-busy people on p5p. You guys (and gals) rock!
List still not complete ;o)
Tels
Math-BigInt-1.999829/examples/0000755403072340010010000000000014163520241015615 5ustar OSPJADomain UsersMath-BigInt-1.999829/examples/1000.txt0000644403072340010010000001615214156375570016762 0ustar OSPJADomain Users# The First 1,000 Primes
# (the 1,000th is 7919)
# For more information on primes see http://www.utm.edu/research/primes
2 3 5 7 11 13 17 19 23 29
31 37 41 43 47 53 59 61 67 71
73 79 83 89 97 101 103 107 109 113
127 131 137 139 149 151 157 163 167 173
179 181 191 193 197 199 211 223 227 229
233 239 241 251 257 263 269 271 277 281
283 293 307 311 313 317 331 337 347 349
353 359 367 373 379 383 389 397 401 409
419 421 431 433 439 443 449 457 461 463
467 479 487 491 499 503 509 521 523 541
547 557 563 569 571 577 587 593 599 601
607 613 617 619 631 641 643 647 653 659
661 673 677 683 691 701 709 719 727 733
739 743 751 757 761 769 773 787 797 809
811 821 823 827 829 839 853 857 859 863
877 881 883 887 907 911 919 929 937 941
947 953 967 971 977 983 991 997 1009 1013
1019 1021 1031 1033 1039 1049 1051 1061 1063 1069
1087 1091 1093 1097 1103 1109 1117 1123 1129 1151
1153 1163 1171 1181 1187 1193 1201 1213 1217 1223
1229 1231 1237 1249 1259 1277 1279 1283 1289 1291
1297 1301 1303 1307 1319 1321 1327 1361 1367 1373
1381 1399 1409 1423 1427 1429 1433 1439 1447 1451
1453 1459 1471 1481 1483 1487 1489 1493 1499 1511
1523 1531 1543 1549 1553 1559 1567 1571 1579 1583
1597 1601 1607 1609 1613 1619 1621 1627 1637 1657
1663 1667 1669 1693 1697 1699 1709 1721 1723 1733
1741 1747 1753 1759 1777 1783 1787 1789 1801 1811
1823 1831 1847 1861 1867 1871 1873 1877 1879 1889
1901 1907 1913 1931 1933 1949 1951 1973 1979 1987
1993 1997 1999 2003 2011 2017 2027 2029 2039 2053
2063 2069 2081 2083 2087 2089 2099 2111 2113 2129
2131 2137 2141 2143 2153 2161 2179 2203 2207 2213
2221 2237 2239 2243 2251 2267 2269 2273 2281 2287
2293 2297 2309 2311 2333 2339 2341 2347 2351 2357
2371 2377 2381 2383 2389 2393 2399 2411 2417 2423
2437 2441 2447 2459 2467 2473 2477 2503 2521 2531
2539 2543 2549 2551 2557 2579 2591 2593 2609 2617
2621 2633 2647 2657 2659 2663 2671 2677 2683 2687
2689 2693 2699 2707 2711 2713 2719 2729 2731 2741
2749 2753 2767 2777 2789 2791 2797 2801 2803 2819
2833 2837 2843 2851 2857 2861 2879 2887 2897 2903
2909 2917 2927 2939 2953 2957 2963 2969 2971 2999
3001 3011 3019 3023 3037 3041 3049 3061 3067 3079
3083 3089 3109 3119 3121 3137 3163 3167 3169 3181
3187 3191 3203 3209 3217 3221 3229 3251 3253 3257
3259 3271 3299 3301 3307 3313 3319 3323 3329 3331
3343 3347 3359 3361 3371 3373 3389 3391 3407 3413
3433 3449 3457 3461 3463 3467 3469 3491 3499 3511
3517 3527 3529 3533 3539 3541 3547 3557 3559 3571
3581 3583 3593 3607 3613 3617 3623 3631 3637 3643
3659 3671 3673 3677 3691 3697 3701 3709 3719 3727
3733 3739 3761 3767 3769 3779 3793 3797 3803 3821
3823 3833 3847 3851 3853 3863 3877 3881 3889 3907
3911 3917 3919 3923 3929 3931 3943 3947 3967 3989
4001 4003 4007 4013 4019 4021 4027 4049 4051 4057
4073 4079 4091 4093 4099 4111 4127 4129 4133 4139
4153 4157 4159 4177 4201 4211 4217 4219 4229 4231
4241 4243 4253 4259 4261 4271 4273 4283 4289 4297
4327 4337 4339 4349 4357 4363 4373 4391 4397 4409
4421 4423 4441 4447 4451 4457 4463 4481 4483 4493
4507 4513 4517 4519 4523 4547 4549 4561 4567 4583
4591 4597 4603 4621 4637 4639 4643 4649 4651 4657
4663 4673 4679 4691 4703 4721 4723 4729 4733 4751
4759 4783 4787 4789 4793 4799 4801 4813 4817 4831
4861 4871 4877 4889 4903 4909 4919 4931 4933 4937
4943 4951 4957 4967 4969 4973 4987 4993 4999 5003
5009 5011 5021 5023 5039 5051 5059 5077 5081 5087
5099 5101 5107 5113 5119 5147 5153 5167 5171 5179
5189 5197 5209 5227 5231 5233 5237 5261 5273 5279
5281 5297 5303 5309 5323 5333 5347 5351 5381 5387
5393 5399 5407 5413 5417 5419 5431 5437 5441 5443
5449 5471 5477 5479 5483 5501 5503 5507 5519 5521
5527 5531 5557 5563 5569 5573 5581 5591 5623 5639
5641 5647 5651 5653 5657 5659 5669 5683 5689 5693
5701 5711 5717 5737 5741 5743 5749 5779 5783 5791
5801 5807 5813 5821 5827 5839 5843 5849 5851 5857
5861 5867 5869 5879 5881 5897 5903 5923 5927 5939
5953 5981 5987 6007 6011 6029 6037 6043 6047 6053
6067 6073 6079 6089 6091 6101 6113 6121 6131 6133
6143 6151 6163 6173 6197 6199 6203 6211 6217 6221
6229 6247 6257 6263 6269 6271 6277 6287 6299 6301
6311 6317 6323 6329 6337 6343 6353 6359 6361 6367
6373 6379 6389 6397 6421 6427 6449 6451 6469 6473
6481 6491 6521 6529 6547 6551 6553 6563 6569 6571
6577 6581 6599 6607 6619 6637 6653 6659 6661 6673
6679 6689 6691 6701 6703 6709 6719 6733 6737 6761
6763 6779 6781 6791 6793 6803 6823 6827 6829 6833
6841 6857 6863 6869 6871 6883 6899 6907 6911 6917
6947 6949 6959 6961 6967 6971 6977 6983 6991 6997
7001 7013 7019 7027 7039 7043 7057 7069 7079 7103
7109 7121 7127 7129 7151 7159 7177 7187 7193 7207
7211 7213 7219 7229 7237 7243 7247 7253 7283 7297
7307 7309 7321 7331 7333 7349 7351 7369 7393 7411
7417 7433 7451 7457 7459 7477 7481 7487 7489 7499
7507 7517 7523 7529 7537 7541 7547 7549 7559 7561
7573 7577 7583 7589 7591 7603 7607 7621 7639 7643
7649 7669 7673 7681 7687 7691 7699 7703 7717 7723
7727 7741 7753 7757 7759 7789 7793 7817 7823 7829
7841 7853 7867 7873 7877 7879 7883 7901 7907 7919
Math-BigInt-1.999829/examples/bigprimes.pl0000755403072340010010000001017114156375570020155 0ustar OSPJADomain Users#!/usr/bin/perl -w
use Test;
BEGIN { plan tests => 17; }
use lib '../lib'; # comment out to use old module
#use lib '../../old/Math-BigInt-0.01/lib'; # for old version
use strict;
#use Math::BigInt;
use Math::BigInt qw/:constant/;
#use Math::BigInt qw/calc BitVect :constant/;
print "# Using Math::BigInt v",$Math::BigInt::VERSION,"\n";
# calculate some sample prime numbers from
# http://www.utm.edu/research/primes/largest.html
# also: http://www-stud.enst.fr/~bellard/mersenne.html
# (c takes 1 minute on 800 Mhz, so Perl will take..ages..)
my ($x,$y,$z);
my $two = Math::BigInt->new(2);
# some new() are to make stop Perl from calculating things like 1234 ** 4321
# at compile time. (we want to see run-time behaviour)
# Also there is len(), since the old BigInt has not got length() and we want
# this script to be comparable between old and new version.
##############################################################################
# Todo: these do not complete in reasonable time:
# $x = $two ** 6972593; $x--; #ok (len($x),'2098960');
# $x = $two ** 3021377; $x--; #ok (len($x),'909526');
# $x = $two ** 756839; $x--; #ok (len($x),'227832');
# $x = 1041870 ** 32768; $x++; #ok (len($x),'197192');
##############################################################################
# but these do:
# some twin primes (first in list at 03/2001)
$x = ($two ** 80025) * 665551035; $x++; $y = $x-2; ok (len($x),'24099');
$x = ($two ** 66443) * 1693965; $x++; $y = $x-2; ok (len($x),'20008');
$x = ($two ** 64955) * 83475759; $x++; $y = $x-2; ok (len($x),'19562');
# ...
$x = ($two ** 38880) * 242206083; $x++; $y = $x-2; ok (len($x),'11713');
##############################################################################
# Sophie Germain primes
# todo: does not finish after 30 m on 800 Mhz
# $x = Math::BigInt->new(72021)**223630; $x--; ok (len($x),'7119');
##############################################################################
# some quadruplet primes...
# 3510160221387831655*(2^3363-2^1121)-6*2^1121-7
$x = '3510160221387831655' * (2 ** 3363 - 2**1121) - 6*(2**1121);
my @q = ( $x-7,$x-5,$x-1,$x+1);
ok (len($q[0]),'1031');
ok (len($q[1]),'1031');
ok (len($q[2]),'1031');
ok (len($q[3]),'1031');
##############################################################################
# some real weird primes:
# (2^3833-1)/(14193959303*340789152474053904109001)
$x = Math::BigInt->new('340789152474053904109001');
$x *= '14193959303';
$x = (2**3833-1) / $x;
ok (len($x),'1121');
#(2^4751-1)/(268982617*3274778783*629530076753*81630665742097*1507074535068001)
$x = Math::BigInt->new('268982617');
$x = $x * '3274778783' * '629530076753' * '81630665742097' * '1507074535068001';
$x = ((2**4751)-1) / $x;
ok (len($x),'1372');
# 2^7039-1)/ (1252943*1057032553*8541573097*218216841131937276721
$x = Math::BigInt->new('1252943')*'1057032553'*'8541573097';
$x *= '218216841131937276721';
$x = ((2**7039)-1) / $x;
ok (len($x),'2074');
# 5616^1153-1)/5615
$x = Math::BigInt->new(5616) ** 1153; $x--; $x /= 5616;
ok (len($x),'4320');
# (7147^2161-1)/7146
$x = Math::BigInt->new(7147) ** 2161; $x--; $x /= 7146;
ok (len($x),'8325');
# 16*R(5700)*(150093*10^8000+1)+1 # most ending 7's
# gives error in BigInt
$x = 16 * R(5700);
$x *= (150093*(Math::BigInt->new(10)**8000))+1; $x++;
ok (len($x),'13706');
# 2*11^13359+1
$x = 2*(Math::BigInt->new(11)**13359)+1;
ok(len($x),'13913');
# 10^14800+5*(10^8880+10^5920)+7*10^7400+1
# palindrome
$x = Math::BigInt->new(10) ** 14800;
$x += 5*((Math::BigInt->new(10) ** 8800) + (Math::BigInt->new(10)**5920));
$x += 7*(Math::BigInt->new(10) ** 7400);
ok(len($x),'14801');
$y = "$x"; $y =~ s/^\+//;
my $left = substr("$y",7400);
my $right = substr("$y",-7401);
ok($left,$right);
# EOF
##############################################################################
# some helper functions
sub R
{
my $x = shift;
# These numbers have a decimal expansion of n '1's,
# and are usually called "repunits".
return ((Math::BigInt->new(10) ** $x) - 1)/9;
}
sub len
{
# old bigint has not got length, so use "" and strip it's sign
my $x = shift;
$x = "$x"; $x =~ s/^\+//;
return length($x);
}
Math-BigInt-1.999829/examples/prime.pl0000755403072340010010000000366114156375570017316 0ustar OSPJADomain Users#!/usr/bin/perl -w
BEGIN { unshift @INC, '../lib'; } # uncomment to use old, org version
$| = 1;
use Math::BigInt;
# this is a complicated version of the prime number sieve.
# It is not optimized (since we want to benchmark as many features as
# possible).
$amount = Math::BigInt->new( shift || 1000000 );
@primes = (1,1,0); # any not defined number is prime, 0,1 are not, but 2 is
my $prime = Math::BigInt->new (3); # start
# the loop below is faster in the old version than in the new, since it is
# the worst case for new lib: small numbers and lot's of bstr()/new().
# It also slows down the benchmark too much so we use slightly faster int here
$r = 0; my $a = $amount->numify();
for ($i = 3; $i < $a; $i++) # int version
{
$primes[$i] = $r; $r = 1-$r;
}
# find primes
OUTER:
while ($prime < $amount)
{
# find first unmarked, it is the next prime
$cur = $prime;
while ($primes[$cur])
{
$cur += 2; last OUTER if $cur >= $amount; # no more to do
}
# $cur is now new prime
$str = "$cur"; $str =~ s/\+//; # unify output for comapre
#print "$str $prime $amount\n";
# now strike out all multiples of $cur
$add = $cur*2;
$prime = $cur + 2; # next round start two higher
$cur += $add;
while ($cur < $amount)
{
$primes[$cur] = 1; $cur += $add;
}
}
$i = 0;
foreach (@primes)
{
push @real_primes, $i if $primes[$i] == 0;
$i++;
}
# uncomment to print em:
# foreach (@real_primes) { print "$_\n"; }
print "last prime: $real_primes[-1]\n";
# check against text
open FILE, '1000.txt' or die "Can't read 1000.txt: $!";
my @test;
while ()
{
next if /^#/;
next if /^\s*$/;
$_ =~ s/\s+/ /g;
$_ =~ s/^\s+//;
$_ =~ s/\s+$//;
push @test, split /\s+/,$_;
}
close FILE;
my $i = 0;
foreach (@real_primes)
{
print "oups: $i: $test[$i] != $real_primes[$i]\n"
if $test[$i] != $real_primes[$i]; $i++;
last if $i >= 1000;
}
print "done\n";
Math-BigInt-1.999829/GOALS0000644403072340010010000000253114156375567014615 0ustar OSPJADomain UsersThis file contains a short description of what the goals of this project are,
building guidelines etc. This was born after discussions with John Peacock, who
provided helpfull feedback.
* KISS - Keep It Simple, Stupid!
* Favour correctness over speed
* Make your code maintable, so avoid Copy&Paste, unclear constructs, read-only
code and special hacks whenever possible
* Optimize more for the average case than the worst, while trying to avoid
performance hits for the worst case.
The average case is more for longer numbers than short, based on the
assumption that if you wanted to add 1 and 2 _fast_ together, you wouldn't
use BigInt nor Perl, now would you? ;)
(Or in other words: Time saved in one case of a large number may be
multitudes of what you can waste on a small number)
* Make subclassing as easy and painless as possible. This means clean
inheritance and overload section, no C&P code etc.
* Keep the interface as consistent and easy as possible.
Secondary goals:
* Make mixing of classes work, like in:
$x = Math::BigFloat->new(10);
$y = Math::BigInt->new(2);
$z = $x / $y; # $z = Math::BigFloat = 5
* Make auto-upgrading/downgrading work
See also BUGS.
Please send me test-reports, your experiences with this and your ideas - I love
to hear about my work!
Tels
Math-BigInt-1.999829/HISTORY0000644403072340010010000001136614156375567015117 0ustar OSPJADomain UsersThis file contains all the changes and bugfixes from the original version of
BigInt/BigFloat to the rewritten one. For what has changed in the latest
version see NEW and for a complete list of changes see the file CHANGES.
v1.82:
general:
+ It is subsequent faster than the original in many places
+ Use more than 16 bit at a time, greater BASELEN for 64 bit systems
+ overload for things like +=
+ special operations like binc()
+ many optimizations and shortcuts in normal operations
+ Can use Math::BigInt lib => 'name'; for Pari, GMP, Bit::Vector or others
+ regression test suite greatly enhanced to cover more problematic cases
+ added example scripts (prime.pl, bigprimes.pl, hailstone.pl)
+ documentation fixed and greatly enhanced
+ BigInt is sub-classable with very little effort, see M::S or M::BF
+ subclasses of Math::BigInt know all the same methods, so that you can call
$x->some_method() without having to know which type of class $x is
+ added infinity handling
+ much better NaN handling
caveats:
+ bstr() and stringify now drop the leading '+' (to make overloaded cmp work
as expected when cmp'aring to scalars and other objects (read: bugfix)
+ due to the dropping of '+' the string sort order has changed. It is now
compatible to the way perl sorts it's strings.
+ spaces are no longer allowed in a number (but may precede or follow it)
!! You can always make a subclass and change all these things quite easily !!
input:
+ underscores are now valid between any two digits (in hex/binary input, too)
+ integers of the form 1E2, 1.23E2, 2.00 etc now valid for BigInt.pm, too
+ hexadecimal numbers of the form 0xabcdefABCDEF0123456789
+ binary numbers of the form 0b01010101101000001000100101
+ octal numbers can be input via from_oct()
output:
+ as_hex(), as_bin() and as_oct() for easier conversation between bases
bugs and buglets fixed over Mark's original:
+ 0**0 gave NaN instead of 1
+ -1**y gave -1 instead of +1 for even y
+ fsqrt() gave slightly wrong results (like for fsqrt(9))
+ +x/0 is now +inf, -x/0 is -inf (both were NaN), as well as other inf cases
+ mod/div for negative numbers were incompatible to Perl's way
+ added P. Prymmer's OS/390 '/1e5 vs *1e-5' patch w/o the performance snag
+ incorporated all the patches to the core modules by John Peacock
+ BigFloat::bxxx() works as well as BigFloat::fxxx()
+ Math::BigInt->new(10) / Math::BigFloat->new(2) returned NaN (ditto for
other subclasses of Math::BigInt)
+ $a = new Math::BigInt; creates now a +0, while "" still gives a NaN
This suppresses all warnings on undef arguments. Wether this is better...
+ import() would always use "Math::BigInt" and clash with Exporter
+ use Math::BigInt qw(bneg); $a = bneg('1234'); etc did not work at all
+ $x->xxx() now modifies $x in all cases of modifiers and actually returns
the same $x (e.g. not a plain scalar or a different reference). All
testing routines leave $x alone. bpow(), bmod(), fround(), ffround() etc
were broken in this regard.
accuracy and precision:
+ there is now support for both accuracy (significant digits) and precision
(fixed number of digits after decimal point), which by default is off
+ objects/numbers now can have a local accuracy/precision
internal fixes:
+ uses a blessed hash ref instead scalar ref (easier subclassable)
+ my instead of local
+ use strict and -w
+ s/$[/0/ (after all, $[ = 1; in main does not effect this package)
+ $# partially removed ($#y is scalar @y -1, $#$y is scalar @$y-1 - ugh!)
+ added LICENSE section and file
new stuff:
+ MBF: :constant works now
+ MBI: :constant picks up binary and hexadecimal constants
+ brsft()/blsft() also can do other bases than 2
+ bacmp (acmp), because needed for more efficient add()
+ bzero(), bnan(), bone(), binf()
+ binc(), bdec(), bfac()
+ is_zero(), is_nan(), is_one(), is_odd(), is_even(), is_inf(), is_int()
+ digit(), length(), copy()
+ as_number() (alias: as_int()), as_hex(), as_bin()
+ is_positive(), is_negative() (alias: is_pos() and is_neg())
+ mantissa(), exponent(), parts(), sign()
+ bgcd() accepts now lists, blcm() (also accepts lists)
+ flog()/blog() for overloading of log()
+ fexp()/bexp() for overloading of exp()
+ round(accuracy,precision,mode) round to accuracy/precision using mode
+ MBF: fpow(), fmod(), fdiv() in list context (Thanx J. Peacock)
+ fpow() can now handle non-integer arguments, like in fpow(2.1 ** 0.2)
+ MBI: bsqrt()
+ bmodpow(), bmodinv() (Thanx John Borwick)
+ bfloor(), bceil(), broot()
+ CORE cos()/sin()/exp()/atan2() now work when passed BigInts or BigFloats
Please send me test-reports, your experiences with this and your ideas - I love
to hear about my work!
Tels
Math-BigInt-1.999829/lib/0000755403072340010010000000000014163520241014545 5ustar OSPJADomain UsersMath-BigInt-1.999829/lib/Math/0000755403072340010010000000000014163520241015436 5ustar OSPJADomain UsersMath-BigInt-1.999829/lib/Math/BigFloat.pm0000644403072340010010000061573614163124267017515 0ustar OSPJADomain Userspackage Math::BigFloat;
#
# Mike grinned. 'Two down, infinity to go' - Mike Nostrus in 'Before and After'
#
# The following hash values are used internally:
# sign : "+", "-", "+inf", "-inf", or "NaN" if not a number
# _m : mantissa ($LIB thingy)
# _es : sign of _e
# _e : exponent ($LIB thingy)
# _a : accuracy
# _p : precision
use 5.006001;
use strict;
use warnings;
use Carp qw< carp croak >;
use Scalar::Util qw< blessed >;
use Math::BigInt qw< >;
our $VERSION = '1.999829';
require Exporter;
our @ISA = qw/Math::BigInt/;
our @EXPORT_OK = qw/bpi/;
# $_trap_inf/$_trap_nan are internal and should never be accessed from outside
our ($AUTOLOAD, $accuracy, $precision, $div_scale, $round_mode, $rnd_mode,
$upgrade, $downgrade, $_trap_nan, $_trap_inf);
use overload
# overload key: with_assign
'+' => sub { $_[0] -> copy() -> badd($_[1]); },
'-' => sub { my $c = $_[0] -> copy();
$_[2] ? $c -> bneg() -> badd($_[1])
: $c -> bsub($_[1]); },
'*' => sub { $_[0] -> copy() -> bmul($_[1]); },
'/' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bdiv($_[0])
: $_[0] -> copy() -> bdiv($_[1]); },
'%' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bmod($_[0])
: $_[0] -> copy() -> bmod($_[1]); },
'**' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bpow($_[0])
: $_[0] -> copy() -> bpow($_[1]); },
'<<' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> blsft($_[0])
: $_[0] -> copy() -> blsft($_[1]); },
'>>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> brsft($_[0])
: $_[0] -> copy() -> brsft($_[1]); },
# overload key: assign
'+=' => sub { $_[0] -> badd($_[1]); },
'-=' => sub { $_[0] -> bsub($_[1]); },
'*=' => sub { $_[0] -> bmul($_[1]); },
'/=' => sub { scalar $_[0] -> bdiv($_[1]); },
'%=' => sub { $_[0] -> bmod($_[1]); },
'**=' => sub { $_[0] -> bpow($_[1]); },
'<<=' => sub { $_[0] -> blsft($_[1]); },
'>>=' => sub { $_[0] -> brsft($_[1]); },
# 'x=' => sub { },
# '.=' => sub { },
# overload key: num_comparison
'<' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> blt($_[0])
: $_[0] -> blt($_[1]); },
'<=' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> ble($_[0])
: $_[0] -> ble($_[1]); },
'>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bgt($_[0])
: $_[0] -> bgt($_[1]); },
'>=' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bge($_[0])
: $_[0] -> bge($_[1]); },
'==' => sub { $_[0] -> beq($_[1]); },
'!=' => sub { $_[0] -> bne($_[1]); },
# overload key: 3way_comparison
'<=>' => sub { my $cmp = $_[0] -> bcmp($_[1]);
defined($cmp) && $_[2] ? -$cmp : $cmp; },
'cmp' => sub { $_[2] ? "$_[1]" cmp $_[0] -> bstr()
: $_[0] -> bstr() cmp "$_[1]"; },
# overload key: str_comparison
# 'lt' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrlt($_[0])
# : $_[0] -> bstrlt($_[1]); },
#
# 'le' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrle($_[0])
# : $_[0] -> bstrle($_[1]); },
#
# 'gt' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrgt($_[0])
# : $_[0] -> bstrgt($_[1]); },
#
# 'ge' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrge($_[0])
# : $_[0] -> bstrge($_[1]); },
#
# 'eq' => sub { $_[0] -> bstreq($_[1]); },
#
# 'ne' => sub { $_[0] -> bstrne($_[1]); },
# overload key: binary
'&' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> band($_[0])
: $_[0] -> copy() -> band($_[1]); },
'&=' => sub { $_[0] -> band($_[1]); },
'|' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bior($_[0])
: $_[0] -> copy() -> bior($_[1]); },
'|=' => sub { $_[0] -> bior($_[1]); },
'^' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bxor($_[0])
: $_[0] -> copy() -> bxor($_[1]); },
'^=' => sub { $_[0] -> bxor($_[1]); },
# '&.' => sub { },
# '&.=' => sub { },
# '|.' => sub { },
# '|.=' => sub { },
# '^.' => sub { },
# '^.=' => sub { },
# overload key: unary
'neg' => sub { $_[0] -> copy() -> bneg(); },
# '!' => sub { },
'~' => sub { $_[0] -> copy() -> bnot(); },
# '~.' => sub { },
# overload key: mutators
'++' => sub { $_[0] -> binc() },
'--' => sub { $_[0] -> bdec() },
# overload key: func
'atan2' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> batan2($_[0])
: $_[0] -> copy() -> batan2($_[1]); },
'cos' => sub { $_[0] -> copy() -> bcos(); },
'sin' => sub { $_[0] -> copy() -> bsin(); },
'exp' => sub { $_[0] -> copy() -> bexp($_[1]); },
'abs' => sub { $_[0] -> copy() -> babs(); },
'log' => sub { $_[0] -> copy() -> blog(); },
'sqrt' => sub { $_[0] -> copy() -> bsqrt(); },
'int' => sub { $_[0] -> copy() -> bint(); },
# overload key: conversion
'bool' => sub { $_[0] -> is_zero() ? '' : 1; },
'""' => sub { $_[0] -> bstr(); },
'0+' => sub { $_[0] -> numify(); },
'=' => sub { $_[0] -> copy(); },
;
##############################################################################
# global constants, flags and assorted stuff
# the following are public, but their usage is not recommended. Use the
# accessor methods instead.
# class constants, use Class->constant_name() to access
# one of 'even', 'odd', '+inf', '-inf', 'zero', 'trunc' or 'common'
$round_mode = 'even';
$accuracy = undef;
$precision = undef;
$div_scale = 40;
$upgrade = undef;
$downgrade = undef;
# the package we are using for our private parts, defaults to:
# Math::BigInt->config('lib')
my $LIB = 'Math::BigInt::Calc';
# are NaNs ok? (otherwise it dies when encountering an NaN) set w/ config()
$_trap_nan = 0;
# the same for infinity
$_trap_inf = 0;
# constant for easier life
my $nan = 'NaN';
my $IMPORT = 0; # was import() called yet? used to make require work
# some digits of accuracy for blog(undef, 10); which we use in blog() for speed
my $LOG_10 =
'2.3025850929940456840179914546843642076011014886287729760333279009675726097';
my $LOG_10_A = length($LOG_10)-1;
# ditto for log(2)
my $LOG_2 =
'0.6931471805599453094172321214581765680755001343602552541206800094933936220';
my $LOG_2_A = length($LOG_2)-1;
my $HALF = '0.5'; # made into an object if nec.
##############################################################################
# the old code had $rnd_mode, so we need to support it, too
sub TIESCALAR {
my ($class) = @_;
bless \$round_mode, $class;
}
sub FETCH {
return $round_mode;
}
sub STORE {
$rnd_mode = $_[0]->round_mode($_[1]);
}
BEGIN {
# when someone sets $rnd_mode, we catch this and check the value to see
# whether it is valid or not.
$rnd_mode = 'even';
tie $rnd_mode, 'Math::BigFloat';
# we need both of them in this package:
*as_int = \&as_number;
}
sub DESTROY {
# going through AUTOLOAD for every DESTROY is costly, avoid it by empty sub
}
sub AUTOLOAD {
# make fxxx and bxxx both work by selectively mapping fxxx() to MBF::bxxx()
my $name = $AUTOLOAD;
$name =~ s/(.*):://; # split package
my $c = $1 || __PACKAGE__;
no strict 'refs';
$c->import() if $IMPORT == 0;
if (!_method_alias($name)) {
if (!defined $name) {
# delayed load of Carp and avoid recursion
croak("$c: Can't call a method without name");
}
if (!_method_hand_up($name)) {
# delayed load of Carp and avoid recursion
croak("Can't call $c\-\>$name, not a valid method");
}
# try one level up, but subst. bxxx() for fxxx() since MBI only got bxxx()
$name =~ s/^f/b/;
return &{"Math::BigInt"."::$name"}(@_);
}
my $bname = $name;
$bname =~ s/^f/b/;
$c .= "::$name";
*{$c} = \&{$bname};
&{$c}; # uses @_
}
##############################################################################
{
# valid method aliases for AUTOLOAD
my %methods = map { $_ => 1 }
qw / fadd fsub fmul fdiv fround ffround fsqrt fmod fstr fsstr fpow fnorm
fint facmp fcmp fzero fnan finf finc fdec ffac fneg
fceil ffloor frsft flsft fone flog froot fexp
/;
# valid methods that can be handed up (for AUTOLOAD)
my %hand_ups = map { $_ => 1 }
qw / is_nan is_inf is_negative is_positive is_pos is_neg
accuracy precision div_scale round_mode fabs fnot
objectify upgrade downgrade
bone binf bnan bzero
bsub
/;
sub _method_alias { exists $methods{$_[0]||''}; }
sub _method_hand_up { exists $hand_ups{$_[0]||''}; }
}
sub isa {
my ($self, $class) = @_;
return if $class =~ /^Math::BigInt/; # we aren't one of these
UNIVERSAL::isa($self, $class);
}
sub config {
# return (later set?) configuration data as hash ref
my $class = shift || 'Math::BigFloat';
# Getter/accessor.
if (@_ == 1 && ref($_[0]) ne 'HASH') {
my $param = shift;
return $class if $param eq 'class';
return $LIB if $param eq 'with';
return $class->SUPER::config($param);
}
# Setter.
my $cfg = $class->SUPER::config(@_);
# now we need only to override the ones that are different from our parent
$cfg->{class} = $class;
$cfg->{with} = $LIB;
$cfg;
}
###############################################################################
# Constructor methods
###############################################################################
sub new {
# Create a new Math::BigFloat object from a string or another bigfloat object.
# _e: exponent
# _m: mantissa
# sign => ("+", "-", "+inf", "-inf", or "NaN")
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Although this use has been discouraged for more than 10 years, people
# apparently still use it, so we still support it.
return $class -> bzero() unless @_;
my ($wanted, @r) = @_;
if (!defined($wanted)) {
#if (warnings::enabled("uninitialized")) {
# warnings::warn("uninitialized",
# "Use of uninitialized value in new()");
#}
return $class -> bzero(@r);
}
if (!ref($wanted) && $wanted eq "") {
#if (warnings::enabled("numeric")) {
# warnings::warn("numeric",
# q|Argument "" isn't numeric in new()|);
#}
#return $class -> bzero(@r);
return $class -> bnan(@r);
}
# Initialize a new object.
$self = bless {}, $class unless $selfref;
# The first following ought to work. However, it causes a 'Deep recursion on
# subroutine "Math::BigFloat::as_number"' in some tests. Fixme!
if (defined(blessed($wanted)) && $wanted -> isa('Math::BigFloat')) {
#if (defined(blessed($wanted)) && UNIVERSAL::isa($wanted, 'Math::BigFloat')) {
$self -> {sign} = $wanted -> {sign};
$self -> {_m} = $LIB -> _copy($wanted -> {_m});
$self -> {_es} = $wanted -> {_es};
$self -> {_e} = $LIB -> _copy($wanted -> {_e});
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
# Shortcut for Math::BigInt and its subclasses. This should be improved.
if (defined(blessed($wanted))) {
if ($wanted -> isa('Math::BigInt')) {
$self->{sign} = $wanted -> {sign};
$self->{_m} = $LIB -> _copy($wanted -> {value});
$self->{_es} = '+';
$self->{_e} = $LIB -> _zero();
return $self -> bnorm();
}
if ($wanted -> can("as_number")) {
$self->{sign} = $wanted -> sign();
$self->{_m} = $wanted -> as_number() -> {value};
$self->{_es} = '+';
$self->{_e} = $LIB -> _zero();
return $self -> bnorm();
}
}
# Handle Infs.
if ($wanted =~ /^\s*([+-]?)inf(inity)?\s*\z/i) {
return $downgrade->new($wanted) if $downgrade;
my $sgn = $1 || '+';
$self = $class -> binf($sgn);
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
# Handle explicit NaNs (not the ones returned due to invalid input).
if ($wanted =~ /^\s*([+-]?)nan\s*\z/i) {
return $downgrade->new($wanted) if $downgrade;
$self = $class -> bnan();
$self->round(@r) unless @r >= 2 && !defined $r[0] && !defined $r[1];
return $self;
}
# Shortcut for simple forms like '123' that have no trailing zeros.
if ($wanted =~ / ^
\s* # optional leading whitespace
( [+-]? ) # optional sign
0* # optional leading zeros
( [1-9] (?: [0-9]* [1-9] )? ) # significand
\s* # optional trailing whitespace
$
/x)
{
return $downgrade->new($1 . $2) if $downgrade;
$self->{sign} = $1 || '+';
$self->{_m} = $LIB -> _new($2);
$self->{_es} = '+';
$self->{_e} = $LIB -> _zero();
$self->round(@r) unless @r >= 2 && !defined $r[0] && !defined $r[1];
return $self;
}
my @parts;
if (
# Handle hexadecimal numbers. We auto-detect hexadecimal numbers if they
# have a "0x", "0X", "x", or "X" prefix, cf. CORE::oct().
$wanted =~ /^\s*[+-]?0?[Xx]/ and
@parts = $class -> _hex_str_to_lib_parts($wanted)
or
# Handle octal numbers. We auto-detect octal numbers if they have a
# "0o", "0O", "o", "O" prefix, cf. CORE::oct().
$wanted =~ /^\s*[+-]?0?[Oo]/ and
@parts = $class -> _oct_str_to_lib_parts($wanted)
or
# Handle binary numbers. We auto-detect binary numbers if they have a
# "0b", "0B", "b", or "B" prefix, cf. CORE::oct().
$wanted =~ /^\s*[+-]?0?[Bb]/ and
@parts = $class -> _bin_str_to_lib_parts($wanted)
or
# At this point, what is left are decimal numbers that aren't handled
# above and octal floating point numbers that don't have any of the
# "0o", "0O", "o", or "O" prefixes. First see if it is a decimal number.
@parts = $class -> _dec_str_to_lib_parts($wanted)
or
# See if it is an octal floating point number. The extra check is
# included because _oct_str_to_lib_parts() accepts octal numbers that
# don't have a prefix (this is needed to make it work with, e.g.,
# from_oct() that don't require a prefix). However, Perl requires a
# prefix for octal floating point literals. For example, "1p+0" is not
# valid, but "01p+0" and "0__1p+0" are.
$wanted =~ /^\s*[+-]?0_*\d/ and
@parts = $class -> _oct_str_to_lib_parts($wanted))
{
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+' && $downgrade) {
#return $downgrade->new($str, @r);
return $downgrade->new($wanted, @r);
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
# If we get here, the value is neither a valid decimal, binary, octal, or
# hexadecimal number. It is not an explicit Inf or a NaN either.
return $class -> bnan();
}
sub from_dec {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_dec');
my $str = shift;
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
if (my @parts = $class -> _dec_str_to_lib_parts($str)) {
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+' && $downgrade) {
#$str = $parts[0] . $LIB -> _lsft($parts[1], $parts[3], 10);
return $downgrade->new($str, @r);
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
return $self -> bnan(@r);
}
sub from_hex {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_hex');
my $str = shift;
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
if (my @parts = $class -> _hex_str_to_lib_parts($str)) {
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+' && $downgrade) {
#$str = $parts[0] . $LIB -> _lsft($parts[1], $parts[3], 10);
return $downgrade -> from_hex($str, @r);
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
return $self -> bnan(@r);
}
sub from_oct {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_oct');
my $str = shift;
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
if (my @parts = $class -> _oct_str_to_lib_parts($str)) {
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+' && $downgrade) {
#$str = $parts[0] . $LIB -> _lsft($parts[1], $parts[3], 10);
return $downgrade -> from_oct($str, @r);
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
return $self -> bnan(@r);
}
sub from_bin {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_bin');
my $str = shift;
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
if (my @parts = $class -> _bin_str_to_lib_parts($str)) {
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+' && $downgrade) {
#$str = $parts[0] . $LIB -> _lsft($parts[1], $parts[3], 10);
return $downgrade -> from_bin($str, @r);
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
return $self -> bnan(@r);
}
sub from_ieee754 {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_ieee754');
my $in = shift; # input string (or raw bytes)
my $format = shift; # format ("binary32", "decimal64" etc.)
my $enc; # significand encoding (applies only to decimal)
my $k; # storage width in bits
my $b; # base
my @r = @_;
if ($format =~ /^binary(\d+)\z/) {
$k = $1;
$b = 2;
} elsif ($format =~ /^decimal(\d+)(dpd|bcd)?\z/) {
$k = $1;
$b = 10;
$enc = $2 || 'dpd'; # default is dencely-packed decimals (DPD)
} elsif ($format eq 'half') {
$k = 16;
$b = 2;
} elsif ($format eq 'single') {
$k = 32;
$b = 2;
} elsif ($format eq 'double') {
$k = 64;
$b = 2;
} elsif ($format eq 'quadruple') {
$k = 128;
$b = 2;
} elsif ($format eq 'octuple') {
$k = 256;
$b = 2;
} elsif ($format eq 'sexdecuple') {
$k = 512;
$b = 2;
}
if ($b == 2) {
# Get the parameters for this format.
my $p; # precision (in bits)
my $t; # number of bits in significand
my $w; # number of bits in exponent
if ($k == 16) { # binary16 (half-precision)
$p = 11;
$t = 10;
$w = 5;
} elsif ($k == 32) { # binary32 (single-precision)
$p = 24;
$t = 23;
$w = 8;
} elsif ($k == 64) { # binary64 (double-precision)
$p = 53;
$t = 52;
$w = 11;
} else { # binaryN (quadruple-precision and above)
if ($k < 128 || $k != 32 * sprintf('%.0f', $k / 32)) {
croak "Number of bits must be 16, 32, 64, or >= 128 and",
" a multiple of 32";
}
$p = $k - sprintf('%.0f', 4 * log($k) / log(2)) + 13;
$t = $p - 1;
$w = $k - $t - 1;
}
# The maximum exponent, minimum exponent, and exponent bias.
my $emax = Math::BigInt -> new(2) -> bpow($w - 1) -> bdec();
my $emin = 1 - $emax;
my $bias = $emax;
# Undefined input.
unless (defined $in) {
carp("Input is undefined");
return $self -> bzero(@r);
}
# Make sure input string is a string of zeros and ones.
my $len = CORE::length $in;
if (8 * $len == $k) { # bytes
$in = unpack "B*", $in;
} elsif (4 * $len == $k) { # hexadecimal
if ($in =~ /([^\da-f])/i) {
croak "Illegal hexadecimal digit '$1'";
}
$in = unpack "B*", pack "H*", $in;
} elsif ($len == $k) { # bits
if ($in =~ /([^01])/) {
croak "Illegal binary digit '$1'";
}
} else {
croak "Unknown input -- $in";
}
# Split bit string into sign, exponent, and mantissa/significand.
my $sign = substr($in, 0, 1) eq '1' ? '-' : '+';
my $expo = $class -> from_bin(substr($in, 1, $w));
my $mant = $class -> from_bin(substr($in, $w + 1));
my $x;
$expo -> bsub($bias); # subtract bias
if ($expo < $emin) { # zero and subnormals
if ($mant == 0) { # zero
$x = $class -> bzero();
} else { # subnormals
# compute (1/$b)**(N) rather than ($b)**(-N)
$x = $class -> new("0.5"); # 1/$b
$x -> bpow($bias + $t - 1) -> bmul($mant);
$x -> bneg() if $sign eq '-';
}
}
elsif ($expo > $emax) { # inf and nan
if ($mant == 0) { # inf
$x = $class -> binf($sign);
} else { # nan
$x = $class -> bnan();
}
}
else { # normals
$mant = $class -> new(2) -> bpow($t) -> badd($mant);
if ($expo < $t) {
# compute (1/$b)**(N) rather than ($b)**(-N)
$x = $class -> new("0.5"); # 1/$b
$x -> bpow($t - $expo) -> bmul($mant);
} else {
$x = $class -> new(2);
$x -> bpow($expo - $t) -> bmul($mant);
}
$x -> bneg() if $sign eq '-';
}
if ($selfref) {
$self -> {sign} = $x -> {sign};
$self -> {_m} = $x -> {_m};
$self -> {_es} = $x -> {_es};
$self -> {_e} = $x -> {_e};
} else {
$self = $x;
}
return $self -> round(@r);
}
croak("The format '$format' is not yet supported.");
}
sub bzero {
# create/assign '+0'
if (@_ == 0) {
#carp("Using bone() as a function is deprecated;",
# " use bone() as a method instead");
unshift @_, __PACKAGE__;
}
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
$self->import() if $IMPORT == 0; # make require work
return if $selfref && $self->modify('bzero');
$self = bless {}, $class unless $selfref;
$self -> {sign} = '+';
$self -> {_m} = $LIB -> _zero();
$self -> {_es} = '+';
$self -> {_e} = $LIB -> _zero();
# If rounding parameters are given as arguments, use them. If no rounding
# parameters are given, and if called as a class method initialize the new
# instance with the class variables.
if (@_) {
croak "can't specify both accuracy and precision"
if @_ >= 2 && defined $_[0] && defined $_[1];
$self->{_a} = $_[0];
$self->{_p} = $_[1];
} else {
unless($selfref) {
$self->{_a} = $class -> accuracy();
$self->{_p} = $class -> precision();
}
}
return $self;
}
sub bone {
# Create or assign '+1' (or -1 if given sign '-').
if (@_ == 0 || (defined($_[0]) && ($_[0] eq '+' || $_[0] eq '-'))) {
#carp("Using bone() as a function is deprecated;",
# " use bone() as a method instead");
unshift @_, __PACKAGE__;
}
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
$self->import() if $IMPORT == 0; # make require work
return if $selfref && $self->modify('bone');
my $sign = shift;
$sign = defined $sign && $sign =~ /^\s*-/ ? "-" : "+";
$self = bless {}, $class unless $selfref;
$self -> {sign} = $sign;
$self -> {_m} = $LIB -> _one();
$self -> {_es} = '+';
$self -> {_e} = $LIB -> _zero();
# If rounding parameters are given as arguments, use them. If no rounding
# parameters are given, and if called as a class method initialize the new
# instance with the class variables.
if (@_) {
croak "can't specify both accuracy and precision"
if @_ >= 2 && defined $_[0] && defined $_[1];
$self->{_a} = $_[0];
$self->{_p} = $_[1];
} else {
unless($selfref) {
$self->{_a} = $class -> accuracy();
$self->{_p} = $class -> precision();
}
}
return $self;
}
sub binf {
# create/assign a '+inf' or '-inf'
if (@_ == 0 || (defined($_[0]) && !ref($_[0]) &&
$_[0] =~ /^\s*[+-](inf(inity)?)?\s*$/))
{
#carp("Using binf() as a function is deprecated;",
# " use binf() as a method instead");
unshift @_, __PACKAGE__;
}
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
{
no strict 'refs';
if (${"${class}::_trap_inf"}) {
croak("Tried to create +-inf in $class->binf()");
}
}
$self->import() if $IMPORT == 0; # make require work
return if $selfref && $self->modify('binf');
my $sign = shift;
$sign = defined $sign && $sign =~ /^\s*-/ ? "-" : "+";
$self = bless {}, $class unless $selfref;
$self -> {sign} = $sign . 'inf';
$self -> {_m} = $LIB -> _zero();
$self -> {_es} = '+';
$self -> {_e} = $LIB -> _zero();
# If rounding parameters are given as arguments, use them. If no rounding
# parameters are given, and if called as a class method initialize the new
# instance with the class variables.
if (@_) {
croak "can't specify both accuracy and precision"
if @_ >= 2 && defined $_[0] && defined $_[1];
$self->{_a} = $_[0];
$self->{_p} = $_[1];
} else {
unless($selfref) {
$self->{_a} = $class -> accuracy();
$self->{_p} = $class -> precision();
}
}
return $self;
}
sub bnan {
# create/assign a 'NaN'
if (@_ == 0) {
#carp("Using bnan() as a function is deprecated;",
# " use bnan() as a method instead");
unshift @_, __PACKAGE__;
}
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
{
no strict 'refs';
if (${"${class}::_trap_nan"}) {
croak("Tried to create NaN in $class->bnan()");
}
}
$self->import() if $IMPORT == 0; # make require work
return if $selfref && $self->modify('bnan');
$self = bless {}, $class unless $selfref;
$self -> {sign} = $nan;
$self -> {_m} = $LIB -> _zero();
$self -> {_es} = '+';
$self -> {_e} = $LIB -> _zero();
# If rounding parameters are given as arguments, use them. If no rounding
# parameters are given, and if called as a class method initialize the new
# instance with the class variables.
if (@_) {
croak "can't specify both accuracy and precision"
if @_ >= 2 && defined $_[0] && defined $_[1];
$self->{_a} = $_[0];
$self->{_p} = $_[1];
} else {
unless($selfref) {
$self->{_a} = $class -> accuracy();
$self->{_p} = $class -> precision();
}
}
return $self;
}
sub bpi {
# Called as Argument list
# --------- -------------
# Math::BigFloat->bpi() ("Math::BigFloat")
# Math::BigFloat->bpi(10) ("Math::BigFloat", 10)
# $x->bpi() ($x)
# $x->bpi(10) ($x, 10)
# Math::BigFloat::bpi() ()
# Math::BigFloat::bpi(10) (10)
#
# In ambiguous cases, we favour the OO-style, so the following case
#
# $n = Math::BigFloat->new("10");
# $x = Math::BigFloat->bpi($n);
#
# which gives an argument list with the single element $n, is resolved as
#
# $n->bpi();
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
my @r; # rounding paramters
# If bpi() is called as a function ...
#
# This cludge is necessary because we still support bpi() as a function. If
# bpi() is called with either no argument or one argument, and that one
# argument is either undefined or a scalar that looks like a number, then
# we assume bpi() is called as a function.
if (@_ == 0 &&
(defined($self) && !ref($self) && $self =~ /^\s*[+-]?\d/)
||
!defined($self))
{
$r[0] = $self;
$class = __PACKAGE__;
$self = $class -> bzero(@r); # initialize
}
# ... or if bpi() is called as a method ...
else {
@r = @_;
if ($selfref) { # bpi() called as instance method
return $self if $self -> modify('bpi');
} else { # bpi() called as class method
$self = $class -> bzero(@r); # initialize
}
}
($self, @r) = $self -> _find_round_parameters(@r);
# The accuracy, i.e., the number of digits. Pi has one digit before the
# dot, so a precision of 4 digits is equivalent to an accuracy of 5 digits.
my $n = defined $r[0] ? $r[0]
: defined $r[1] ? 1 - $r[1]
: $self -> div_scale();
my $rmode = defined $r[2] ? $r[2] : $self -> round_mode();
my $pi;
if ($n <= 1000) {
# 75 x 14 = 1050 digits
my $all_digits = < new($digits . 'e-' . ($n - 1));
} else {
# For large accuracy, the arctan formulas become very inefficient with
# Math::BigFloat, so use Brent-Salamin (aka AGM or Gauss-Legendre).
# Use a few more digits in the intermediate computations.
$n += 8;
$HALF = $class -> new($HALF) unless ref($HALF);
my ($an, $bn, $tn, $pn) = ($class -> bone, $HALF -> copy() -> bsqrt($n),
$HALF -> copy() -> bmul($HALF), $class -> bone);
while ($pn < $n) {
my $prev_an = $an -> copy();
$an -> badd($bn) -> bmul($HALF, $n);
$bn -> bmul($prev_an) -> bsqrt($n);
$prev_an -> bsub($an);
$tn -> bsub($pn * $prev_an * $prev_an);
$pn -> badd($pn);
}
$an -> badd($bn);
$an -> bmul($an, $n) -> bdiv(4 * $tn, $n);
$an -> round(@r);
$pi = $an;
}
if (defined $r[0]) {
$pi -> accuracy($r[0]);
} elsif (defined $r[1]) {
$pi -> precision($r[1]);
}
for my $key (qw/ sign _m _es _e _a _p /) {
$self -> {$key} = $pi -> {$key};
}
return $self;
}
sub copy {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# If called as a class method, the object to copy is the next argument.
$self = shift() unless $selfref;
my $copy = bless {}, $class;
$copy->{sign} = $self->{sign};
$copy->{_es} = $self->{_es};
$copy->{_m} = $LIB->_copy($self->{_m});
$copy->{_e} = $LIB->_copy($self->{_e});
$copy->{_a} = $self->{_a} if exists $self->{_a};
$copy->{_p} = $self->{_p} if exists $self->{_p};
return $copy;
}
sub as_number {
# return copy as a bigint representation of this Math::BigFloat number
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
return $x if $x->modify('as_number');
if (!$x->isa('Math::BigFloat')) {
# if the object can as_number(), use it
return $x->as_number() if $x->can('as_number');
# otherwise, get us a float and then a number
$x = $x->can('as_float') ? $x->as_float() : $class->new(0+"$x");
}
return Math::BigInt->binf($x->sign()) if $x->is_inf();
return Math::BigInt->bnan() if $x->is_nan();
my $z = $LIB->_copy($x->{_m});
if ($x->{_es} eq '-') { # < 0
$z = $LIB->_rsft($z, $x->{_e}, 10);
} elsif (! $LIB->_is_zero($x->{_e})) { # > 0
$z = $LIB->_lsft($z, $x->{_e}, 10);
}
$z = Math::BigInt->new($x->{sign} . $LIB->_str($z));
$z;
}
###############################################################################
# Boolean methods
###############################################################################
sub is_zero {
# return true if arg (BFLOAT or num_str) is zero
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
($x->{sign} eq '+' && $LIB->_is_zero($x->{_m})) ? 1 : 0;
}
sub is_one {
# return true if arg (BFLOAT or num_str) is +1 or -1 if signis given
my ($class, $x, $sign) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
$sign = '+' if !defined $sign || $sign ne '-';
($x->{sign} eq $sign &&
$LIB->_is_zero($x->{_e}) &&
$LIB->_is_one($x->{_m})) ? 1 : 0;
}
sub is_odd {
# return true if arg (BFLOAT or num_str) is odd or false if even
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
(($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't
($LIB->_is_zero($x->{_e})) &&
($LIB->_is_odd($x->{_m}))) ? 1 : 0;
}
sub is_even {
# return true if arg (BINT or num_str) is even or false if odd
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
(($x->{sign} =~ /^[+-]$/) && # NaN & +-inf aren't
($x->{_es} eq '+') && # 123.45 isn't
($LIB->_is_even($x->{_m}))) ? 1 : 0; # but 1200 is
}
sub is_int {
# return true if arg (BFLOAT or num_str) is an integer
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
(($x->{sign} =~ /^[+-]$/) && # NaN and +-inf aren't
($x->{_es} eq '+')) ? 1 : 0; # 1e-1 => no integer
}
###############################################################################
# Comparison methods
###############################################################################
sub bcmp {
# Compares 2 values. Returns one of undef, <0, =0, >0. (suitable for sort)
# set up parameters
my ($class, $x, $y) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y) = objectify(2, @_);
}
return $upgrade->bcmp($x, $y) if defined $upgrade &&
((!$x->isa($class)) || (!$y->isa($class)));
# Handle all 'nan' cases.
return if ($x->{sign} eq $nan) || ($y->{sign} eq $nan);
# Handle all '+inf' and '-inf' cases.
return 0 if ($x->{sign} eq '+inf' && $y->{sign} eq '+inf' ||
$x->{sign} eq '-inf' && $y->{sign} eq '-inf');
return +1 if $x->{sign} eq '+inf'; # x = +inf and y < +inf
return -1 if $x->{sign} eq '-inf'; # x = -inf and y > -inf
return -1 if $y->{sign} eq '+inf'; # x < +inf and y = +inf
return +1 if $y->{sign} eq '-inf'; # x > -inf and y = -inf
# Handle all cases with opposite signs.
return +1 if $x->{sign} eq '+' && $y->{sign} eq '-'; # also does 0 <=> -y
return -1 if $x->{sign} eq '-' && $y->{sign} eq '+'; # also does -x <=> 0
# Handle all remaining zero cases.
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
# Both arguments are now finite, non-zero numbers with the same sign.
my $cmp;
# The next step is to compare the exponents, but since each mantissa is an
# integer of arbitrary value, the exponents must be normalized by the length
# of the mantissas before we can compare them.
my $mxl = $LIB->_len($x->{_m});
my $myl = $LIB->_len($y->{_m});
# If the mantissas have the same length, there is no point in normalizing the
# exponents by the length of the mantissas, so treat that as a special case.
if ($mxl == $myl) {
# First handle the two cases where the exponents have different signs.
if ($x->{_es} eq '+' && $y->{_es} eq '-') {
$cmp = +1;
} elsif ($x->{_es} eq '-' && $y->{_es} eq '+') {
$cmp = -1;
}
# Then handle the case where the exponents have the same sign.
else {
$cmp = $LIB->_acmp($x->{_e}, $y->{_e});
$cmp = -$cmp if $x->{_es} eq '-';
}
# Adjust for the sign, which is the same for x and y, and bail out if
# we're done.
$cmp = -$cmp if $x->{sign} eq '-'; # 124 > 123, but -124 < -123
return $cmp if $cmp;
}
# We must normalize each exponent by the length of the corresponding
# mantissa. Life is a lot easier if we first make both exponents
# non-negative. We do this by adding the same positive value to both
# exponent. This is safe, because when comparing the exponents, only the
# relative difference is important.
my $ex;
my $ey;
if ($x->{_es} eq '+') {
# If the exponent of x is >= 0 and the exponent of y is >= 0, there is no
# need to do anything special.
if ($y->{_es} eq '+') {
$ex = $LIB->_copy($x->{_e});
$ey = $LIB->_copy($y->{_e});
}
# If the exponent of x is >= 0 and the exponent of y is < 0, add the
# absolute value of the exponent of y to both.
else {
$ex = $LIB->_copy($x->{_e});
$ex = $LIB->_add($ex, $y->{_e}); # ex + |ey|
$ey = $LIB->_zero(); # -ex + |ey| = 0
}
} else {
# If the exponent of x is < 0 and the exponent of y is >= 0, add the
# absolute value of the exponent of x to both.
if ($y->{_es} eq '+') {
$ex = $LIB->_zero(); # -ex + |ex| = 0
$ey = $LIB->_copy($y->{_e});
$ey = $LIB->_add($ey, $x->{_e}); # ey + |ex|
}
# If the exponent of x is < 0 and the exponent of y is < 0, add the
# absolute values of both exponents to both exponents.
else {
$ex = $LIB->_copy($y->{_e}); # -ex + |ey| + |ex| = |ey|
$ey = $LIB->_copy($x->{_e}); # -ey + |ex| + |ey| = |ex|
}
}
# Now we can normalize the exponents by adding lengths of the mantissas.
$ex = $LIB->_add($ex, $LIB->_new($mxl));
$ey = $LIB->_add($ey, $LIB->_new($myl));
# We're done if the exponents are different.
$cmp = $LIB->_acmp($ex, $ey);
$cmp = -$cmp if $x->{sign} eq '-'; # 124 > 123, but -124 < -123
return $cmp if $cmp;
# Compare the mantissas, but first normalize them by padding the shorter
# mantissa with zeros (shift left) until it has the same length as the longer
# mantissa.
my $mx = $x->{_m};
my $my = $y->{_m};
if ($mxl > $myl) {
$my = $LIB->_lsft($LIB->_copy($my), $LIB->_new($mxl - $myl), 10);
} elsif ($mxl < $myl) {
$mx = $LIB->_lsft($LIB->_copy($mx), $LIB->_new($myl - $mxl), 10);
}
$cmp = $LIB->_acmp($mx, $my);
$cmp = -$cmp if $x->{sign} eq '-'; # 124 > 123, but -124 < -123
return $cmp;
}
sub bacmp {
# Compares 2 values, ignoring their signs.
# Returns one of undef, <0, =0, >0. (suitable for sort)
# set up parameters
my ($class, $x, $y) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y) = objectify(2, @_);
}
return $upgrade->bacmp($x, $y) if defined $upgrade &&
((!$x->isa($class)) || (!$y->isa($class)));
# handle +-inf and NaN's
if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/) {
return if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
return 0 if ($x->is_inf() && $y->is_inf());
return 1 if ($x->is_inf() && !$y->is_inf());
return -1;
}
# shortcut
my $xz = $x->is_zero();
my $yz = $y->is_zero();
return 0 if $xz && $yz; # 0 <=> 0
return -1 if $xz && !$yz; # 0 <=> +y
return 1 if $yz && !$xz; # +x <=> 0
# adjust so that exponents are equal
my $lxm = $LIB->_len($x->{_m});
my $lym = $LIB->_len($y->{_m});
my ($xes, $yes) = (1, 1);
$xes = -1 if $x->{_es} ne '+';
$yes = -1 if $y->{_es} ne '+';
# the numify somewhat limits our length, but makes it much faster
my $lx = $lxm + $xes * $LIB->_num($x->{_e});
my $ly = $lym + $yes * $LIB->_num($y->{_e});
my $l = $lx - $ly;
return $l <=> 0 if $l != 0;
# lengths (corrected by exponent) are equal
# so make mantissa equal-length by padding with zero (shift left)
my $diff = $lxm - $lym;
my $xm = $x->{_m}; # not yet copy it
my $ym = $y->{_m};
if ($diff > 0) {
$ym = $LIB->_copy($y->{_m});
$ym = $LIB->_lsft($ym, $LIB->_new($diff), 10);
} elsif ($diff < 0) {
$xm = $LIB->_copy($x->{_m});
$xm = $LIB->_lsft($xm, $LIB->_new(-$diff), 10);
}
$LIB->_acmp($xm, $ym);
}
###############################################################################
# Arithmetic methods
###############################################################################
sub bneg {
# (BINT or num_str) return BINT
# negate number or make a negated number from string
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
return $x if $x->modify('bneg');
# for +0 do not negate (to have always normalized +0). Does nothing for 'NaN'
$x->{sign} =~ tr/+-/-+/ unless ($x->{sign} eq '+' && $LIB->_is_zero($x->{_m}));
$x;
}
sub bnorm {
# adjust m and e so that m is smallest possible
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
return $x if $x->{sign} !~ /^[+-]$/; # inf, nan etc
my $zeros = $LIB->_zeros($x->{_m}); # correct for trailing zeros
if ($zeros != 0) {
my $z = $LIB->_new($zeros);
$x->{_m} = $LIB->_rsft($x->{_m}, $z, 10);
if ($x->{_es} eq '-') {
if ($LIB->_acmp($x->{_e}, $z) >= 0) {
$x->{_e} = $LIB->_sub($x->{_e}, $z);
$x->{_es} = '+' if $LIB->_is_zero($x->{_e});
} else {
$x->{_e} = $LIB->_sub($LIB->_copy($z), $x->{_e});
$x->{_es} = '+';
}
} else {
$x->{_e} = $LIB->_add($x->{_e}, $z);
}
} else {
# $x can only be 0Ey if there are no trailing zeros ('0' has 0 trailing
# zeros). So, for something like 0Ey, set y to 1, and -0 => +0
$x->{sign} = '+', $x->{_es} = '+', $x->{_e} = $LIB->_one()
if $LIB->_is_zero($x->{_m});
}
$x;
}
sub binc {
# increment arg by one
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('binc');
if ($x->{_es} eq '-') {
return $x->badd($class->bone(), @r); # digits after dot
}
if (!$LIB->_is_zero($x->{_e})) # _e == 0 for NaN, inf, -inf
{
# 1e2 => 100, so after the shift below _m has a '0' as last digit
$x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10); # 1e2 => 100
$x->{_e} = $LIB->_zero(); # normalize
$x->{_es} = '+';
# we know that the last digit of $x will be '1' or '9', depending on the
# sign
}
# now $x->{_e} == 0
if ($x->{sign} eq '+') {
$x->{_m} = $LIB->_inc($x->{_m});
return $x->bnorm()->bround(@r);
} elsif ($x->{sign} eq '-') {
$x->{_m} = $LIB->_dec($x->{_m});
$x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # -1 +1 => -0 => +0
return $x->bnorm()->bround(@r);
}
# inf, nan handling etc
$x->badd($class->bone(), @r); # badd() does round
}
sub bdec {
# decrement arg by one
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bdec');
if ($x->{_es} eq '-') {
return $x->badd($class->bone('-'), @r); # digits after dot
}
if (!$LIB->_is_zero($x->{_e})) {
$x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10); # 1e2 => 100
$x->{_e} = $LIB->_zero(); # normalize
$x->{_es} = '+';
}
# now $x->{_e} == 0
my $zero = $x->is_zero();
# <= 0
if (($x->{sign} eq '-') || $zero) {
$x->{_m} = $LIB->_inc($x->{_m});
$x->{sign} = '-' if $zero; # 0 => 1 => -1
$x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # -1 +1 => -0 => +0
return $x->bnorm()->round(@r);
}
# > 0
elsif ($x->{sign} eq '+') {
$x->{_m} = $LIB->_dec($x->{_m});
return $x->bnorm()->round(@r);
}
# inf, nan handling etc
$x->badd($class->bone('-'), @r); # does round
}
sub badd {
# add second arg (BFLOAT or string) to first (BFLOAT) (modifies first)
# return result as BFLOAT
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x->modify('badd');
# inf and NaN handling
if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) {
# NaN first
return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
# inf handling
if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/)) {
# +inf++inf or -inf+-inf => same, rest is NaN
return $x if $x->{sign} eq $y->{sign};
return $x->bnan();
}
# +-inf + something => +inf; something +-inf => +-inf
$x->{sign} = $y->{sign}, return $x if $y->{sign} =~ /^[+-]inf$/;
return $x;
}
return $upgrade->badd($x, $y, @r) if defined $upgrade &&
((!$x->isa($class)) || (!$y->isa($class)));
$r[3] = $y; # no push!
# speed: no add for 0+y or x+0
return $x->bround(@r) if $y->is_zero(); # x+0
if ($x->is_zero()) # 0+y
{
# make copy, clobbering up x (modify in place!)
$x->{_e} = $LIB->_copy($y->{_e});
$x->{_es} = $y->{_es};
$x->{_m} = $LIB->_copy($y->{_m});
$x->{sign} = $y->{sign} || $nan;
return $x->round(@r);
}
# take lower of the two e's and adapt m1 to it to match m2
my $e = $y->{_e};
$e = $LIB->_zero() if !defined $e; # if no BFLOAT?
$e = $LIB->_copy($e); # make copy (didn't do it yet)
my $es;
($e, $es) = _e_sub($e, $x->{_e}, $y->{_es} || '+', $x->{_es});
#($e, $es) = $LIB -> _ssub($e, $y->{_es} || '+', $x->{_e}, $x->{_es});
my $add = $LIB->_copy($y->{_m});
if ($es eq '-') # < 0
{
$x->{_m} = $LIB->_lsft($x->{_m}, $e, 10);
($x->{_e}, $x->{_es}) = _e_add($x->{_e}, $e, $x->{_es}, $es);
#$x->{_m} = $LIB->_lsft($x->{_m}, $e, 10);
#($x->{_e}, $x->{_es}) = $LIB -> _sadd($x->{_e}, $x->{_es}, $e, $es);
} elsif (!$LIB->_is_zero($e)) # > 0
{
$add = $LIB->_lsft($add, $e, 10);
}
# else: both e are the same, so just leave them
if ($x->{sign} eq $y->{sign}) {
# add
$x->{_m} = $LIB->_add($x->{_m}, $add);
} else {
($x->{_m}, $x->{sign}) =
_e_add($x->{_m}, $add, $x->{sign}, $y->{sign});
#($x->{_m}, $x->{sign}) =
# $LIB -> _sadd($x->{_m}, $x->{sign}, $add, $y->{sign});
}
# delete trailing zeros, then round
$x->bnorm()->round(@r);
}
sub bsub {
# (BINT or num_str, BINT or num_str) return BINT
# subtract second arg from first, modify first
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x -> modify('bsub');
return $upgrade -> new($x) -> bsub($upgrade -> new($y), @r)
if defined $upgrade && (!$x -> isa($class) || !$y -> isa($class));
return $x -> round(@r) if $y -> is_zero();
# To correctly handle the lone special case $x -> bsub($x), we note the
# sign of $x, then flip the sign from $y, and if the sign of $x did change,
# too, then we caught the special case:
my $xsign = $x -> {sign};
$y -> {sign} =~ tr/+-/-+/; # does nothing for NaN
if ($xsign ne $x -> {sign}) {
# special case of $x -> bsub($x) results in 0
return $x -> bzero(@r) if $xsign =~ /^[+-]$/;
return $x -> bnan(); # NaN, -inf, +inf
}
$x -> badd($y, @r); # badd does not leave internal zeros
$y -> {sign} =~ tr/+-/-+/; # refix $y (does nothing for NaN)
$x; # already rounded by badd() or no rounding
}
sub bmul {
# multiply two numbers
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x->modify('bmul');
return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
# inf handling
if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) {
return $x->bnan() if $x->is_zero() || $y->is_zero();
# result will always be +-inf:
# +inf * +/+inf => +inf, -inf * -/-inf => +inf
# +inf * -/-inf => -inf, -inf * +/+inf => -inf
return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
return $x->binf('-');
}
return $upgrade->bmul($x, $y, @r) if defined $upgrade &&
((!$x->isa($class)) || (!$y->isa($class)));
# aEb * cEd = (a*c)E(b+d)
$x->{_m} = $LIB->_mul($x->{_m}, $y->{_m});
($x->{_e}, $x->{_es}) = _e_add($x->{_e}, $y->{_e}, $x->{_es}, $y->{_es});
#($x->{_e}, $x->{_es}) = $LIB -> _sadd($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
$r[3] = $y; # no push!
# adjust sign:
$x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
$x->bnorm->round(@r);
}
sub bmuladd {
# multiply two numbers and add the third to the result
# set up parameters
my ($class, $x, $y, $z, @r) = objectify(3, @_);
return $x if $x->modify('bmuladd');
return $x->bnan() if (($x->{sign} eq $nan) ||
($y->{sign} eq $nan) ||
($z->{sign} eq $nan));
# inf handling
if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) {
return $x->bnan() if $x->is_zero() || $y->is_zero();
# result will always be +-inf:
# +inf * +/+inf => +inf, -inf * -/-inf => +inf
# +inf * -/-inf => -inf, -inf * +/+inf => -inf
return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
return $x->binf('-');
}
return $upgrade->bmul($x, $y, @r) if defined $upgrade &&
((!$x->isa($class)) || (!$y->isa($class)));
# aEb * cEd = (a*c)E(b+d)
$x->{_m} = $LIB->_mul($x->{_m}, $y->{_m});
($x->{_e}, $x->{_es}) = _e_add($x->{_e}, $y->{_e}, $x->{_es}, $y->{_es});
#($x->{_e}, $x->{_es}) = $LIB -> _sadd($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
$r[3] = $y; # no push!
# adjust sign:
$x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
# z=inf handling (z=NaN handled above)
$x->{sign} = $z->{sign}, return $x if $z->{sign} =~ /^[+-]inf$/;
# take lower of the two e's and adapt m1 to it to match m2
my $e = $z->{_e};
$e = $LIB->_zero() if !defined $e; # if no BFLOAT?
$e = $LIB->_copy($e); # make copy (didn't do it yet)
my $es;
($e, $es) = _e_sub($e, $x->{_e}, $z->{_es} || '+', $x->{_es});
#($e, $es) = $LIB -> _ssub($e, $z->{_es} || '+', $x->{_e}, $x->{_es});
my $add = $LIB->_copy($z->{_m});
if ($es eq '-') # < 0
{
$x->{_m} = $LIB->_lsft($x->{_m}, $e, 10);
($x->{_e}, $x->{_es}) = _e_add($x->{_e}, $e, $x->{_es}, $es);
#$x->{_m} = $LIB->_lsft($x->{_m}, $e, 10);
#($x->{_e}, $x->{_es}) = $LIB -> _sadd($x->{_e}, $x->{_es}, $e, $es);
} elsif (!$LIB->_is_zero($e)) # > 0
{
$add = $LIB->_lsft($add, $e, 10);
}
# else: both e are the same, so just leave them
if ($x->{sign} eq $z->{sign}) {
# add
$x->{_m} = $LIB->_add($x->{_m}, $add);
} else {
($x->{_m}, $x->{sign}) =
_e_add($x->{_m}, $add, $x->{sign}, $z->{sign});
#($x->{_m}, $x->{sign}) =
# $LIB -> _sadd($x->{_m}, $x->{sign}, $add, $z->{sign});
}
# delete trailing zeros, then round
$x->bnorm()->round(@r);
}
sub bdiv {
# (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return
# (BFLOAT, BFLOAT) (quo, rem) or BFLOAT (only quo)
# set up parameters
my ($class, $x, $y, $a, $p, $r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, $a, $p, $r) = objectify(2, @_);
}
return $x if $x->modify('bdiv');
my $wantarray = wantarray; # call only once
# At least one argument is NaN. This is handled the same way as in
# Math::BigInt -> bdiv().
if ($x -> is_nan() || $y -> is_nan()) {
return $wantarray ? ($x -> bnan(), $class -> bnan()) : $x -> bnan();
}
# Divide by zero and modulo zero. This is handled the same way as in
# Math::BigInt -> bdiv(). See the comment in the code for Math::BigInt ->
# bdiv() for further details.
if ($y -> is_zero()) {
my ($quo, $rem);
if ($wantarray) {
$rem = $x -> copy();
}
if ($x -> is_zero()) {
$quo = $x -> bnan();
} else {
$quo = $x -> binf($x -> {sign});
}
return $wantarray ? ($quo, $rem) : $quo;
}
# Numerator (dividend) is +/-inf. This is handled the same way as in
# Math::BigInt -> bdiv(). See the comment in the code for Math::BigInt ->
# bdiv() for further details.
if ($x -> is_inf()) {
my ($quo, $rem);
$rem = $class -> bnan() if $wantarray;
if ($y -> is_inf()) {
$quo = $x -> bnan();
} else {
my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
$quo = $x -> binf($sign);
}
return $wantarray ? ($quo, $rem) : $quo;
}
# Denominator (divisor) is +/-inf. This is handled the same way as in
# Math::BigInt -> bdiv(), with one exception: In scalar context,
# Math::BigFloat does true division (although rounded), not floored division
# (F-division), so a finite number divided by +/-inf is always zero. See the
# comment in the code for Math::BigInt -> bdiv() for further details.
if ($y -> is_inf()) {
my ($quo, $rem);
if ($wantarray) {
if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
$rem = $x -> copy();
$quo = $x -> bzero();
} else {
$rem = $class -> binf($y -> {sign});
$quo = $x -> bone('-');
}
return ($quo, $rem);
} else {
if ($y -> is_inf()) {
if ($x -> is_nan() || $x -> is_inf()) {
return $x -> bnan();
} else {
return $x -> bzero();
}
}
}
}
# At this point, both the numerator and denominator are finite numbers, and
# the denominator (divisor) is non-zero.
# x == 0?
return wantarray ? ($x, $class->bzero()) : $x if $x->is_zero();
# 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;
my (@params, $scale);
($x, @params) = $x->_find_round_parameters($a, $p, $r, $y);
return $x if $x->is_nan(); # error in _find_round_parameters?
# no rounding at all, so must use fallback
if (scalar @params == 0) {
# simulate old behaviour
$params[0] = $class->div_scale(); # and round to it as accuracy
$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
} else {
# the 4 below is empirical, and there might be cases where it is not
# enough...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
my $rem;
$rem = $class -> bzero() if wantarray;
$y = $class->new($y) unless $y->isa('Math::BigFloat');
my $lx = $LIB -> _len($x->{_m}); my $ly = $LIB -> _len($y->{_m});
$scale = $lx if $lx > $scale;
$scale = $ly if $ly > $scale;
my $diff = $ly - $lx;
$scale += $diff if $diff > 0; # if lx << ly, but not if ly << lx!
# check that $y is not 1 nor -1 and cache the result:
my $y_not_one = !($LIB->_is_zero($y->{_e}) && $LIB->_is_one($y->{_m}));
# flipping the sign of $y will also flip the sign of $x for the special
# case of $x->bsub($x); so we can catch it below:
my $xsign = $x->{sign};
$y->{sign} =~ tr/+-/-+/;
if ($xsign ne $x->{sign}) {
# special case of $x /= $x results in 1
$x->bone(); # "fixes" also sign of $y, since $x is $y
} else {
# correct $y's sign again
$y->{sign} =~ tr/+-/-+/;
# continue with normal div code:
# make copy of $x in case of list context for later remainder calculation
if (wantarray && $y_not_one) {
$rem = $x->copy();
}
$x->{sign} = $x->{sign} ne $y->sign() ? '-' : '+';
# check for / +-1 (+/- 1E0)
if ($y_not_one) {
# promote BigInts and it's subclasses (except when already a Math::BigFloat)
$y = $class->new($y) unless $y->isa('Math::BigFloat');
# calculate the result to $scale digits and then round it
# a * 10 ** b / c * 10 ** d => a/c * 10 ** (b-d)
$x->{_m} = $LIB->_lsft($x->{_m}, $LIB->_new($scale), 10);
$x->{_m} = $LIB->_div($x->{_m}, $y->{_m}); # a/c
# correct exponent of $x
($x->{_e}, $x->{_es}) = _e_sub($x->{_e}, $y->{_e}, $x->{_es}, $y->{_es});
#($x->{_e}, $x->{_es})
# = $LIB -> _ssub($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
# correct for 10**scale
($x->{_e}, $x->{_es}) = _e_sub($x->{_e}, $LIB->_new($scale), $x->{_es}, '+');
#($x->{_e}, $x->{_es})
# = $LIB -> _ssub($x->{_e}, $x->{_es}, $LIB->_new($scale), '+');
$x->bnorm(); # remove trailing 0's
}
} # end else $x != $y
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
delete $x->{_a}; # clear before round
$x->bround($params[0], $params[2]); # then round accordingly
} else {
delete $x->{_p}; # clear before round
$x->bfround($params[1], $params[2]); # then round accordingly
}
if ($fallback) {
# clear a/p after round, since user did not request it
delete $x->{_a}; delete $x->{_p};
}
if (wantarray) {
if ($y_not_one) {
$x -> bfloor();
$rem->bmod($y, @params); # copy already done
}
if ($fallback) {
# clear a/p after round, since user did not request it
delete $rem->{_a}; delete $rem->{_p};
}
return ($x, $rem);
}
$x;
}
sub bmod {
# (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return remainder
# set up parameters
my ($class, $x, $y, $a, $p, $r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, $a, $p, $r) = objectify(2, @_);
}
return $x if $x->modify('bmod');
# At least one argument is NaN. This is handled the same way as in
# Math::BigInt -> bmod().
if ($x -> is_nan() || $y -> is_nan()) {
return $x -> bnan();
}
# Modulo zero. This is handled the same way as in Math::BigInt -> bmod().
if ($y -> is_zero()) {
return $x;
}
# Numerator (dividend) is +/-inf. This is handled the same way as in
# Math::BigInt -> bmod().
if ($x -> is_inf()) {
return $x -> bnan();
}
# Denominator (divisor) is +/-inf. This is handled the same way as in
# Math::BigInt -> bmod().
if ($y -> is_inf()) {
if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
return $x;
} else {
return $x -> binf($y -> sign());
}
}
return $x->bzero() if $x->is_zero()
|| ($x->is_int() &&
# check that $y == +1 or $y == -1:
($LIB->_is_zero($y->{_e}) && $LIB->_is_one($y->{_m})));
my $cmp = $x->bacmp($y); # equal or $x < $y?
if ($cmp == 0) { # $x == $y => result 0
return $x -> bzero($a, $p);
}
# only $y of the operands negative?
my $neg = $x->{sign} ne $y->{sign} ? 1 : 0;
$x->{sign} = $y->{sign}; # calc sign first
if ($cmp < 0 && $neg == 0) { # $x < $y => result $x
return $x -> round($a, $p, $r);
}
my $ym = $LIB->_copy($y->{_m});
# 2e1 => 20
$ym = $LIB->_lsft($ym, $y->{_e}, 10)
if $y->{_es} eq '+' && !$LIB->_is_zero($y->{_e});
# if $y has digits after dot
my $shifty = 0; # correct _e of $x by this
if ($y->{_es} eq '-') # has digits after dot
{
# 123 % 2.5 => 1230 % 25 => 5 => 0.5
$shifty = $LIB->_num($y->{_e}); # no more digits after dot
$x->{_m} = $LIB->_lsft($x->{_m}, $y->{_e}, 10); # 123 => 1230, $y->{_m} is already 25
}
# $ym is now mantissa of $y based on exponent 0
my $shiftx = 0; # correct _e of $x by this
if ($x->{_es} eq '-') # has digits after dot
{
# 123.4 % 20 => 1234 % 200
$shiftx = $LIB->_num($x->{_e}); # no more digits after dot
$ym = $LIB->_lsft($ym, $x->{_e}, 10); # 123 => 1230
}
# 123e1 % 20 => 1230 % 20
if ($x->{_es} eq '+' && !$LIB->_is_zero($x->{_e})) {
$x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10); # es => '+' here
}
$x->{_e} = $LIB->_new($shiftx);
$x->{_es} = '+';
$x->{_es} = '-' if $shiftx != 0 || $shifty != 0;
$x->{_e} = $LIB->_add($x->{_e}, $LIB->_new($shifty)) if $shifty != 0;
# now mantissas are equalized, exponent of $x is adjusted, so calc result
$x->{_m} = $LIB->_mod($x->{_m}, $ym);
$x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # fix sign for -0
$x->bnorm();
if ($neg != 0 && ! $x -> is_zero()) # one of them negative => correct in place
{
my $r = $y - $x;
$x->{_m} = $r->{_m};
$x->{_e} = $r->{_e};
$x->{_es} = $r->{_es};
$x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # fix sign for -0
$x->bnorm();
}
$x->round($a, $p, $r, $y); # round and return
}
sub bmodpow {
# takes a very large number to a very large exponent in a given very
# large modulus, quickly, thanks to binary exponentiation. Supports
# negative exponents.
my ($class, $num, $exp, $mod) = objectify(3, @_);
return $num if $num->modify('bmodpow');
# check modulus for valid values
return $num->bnan() if ($mod->{sign} ne '+' # NaN, -, -inf, +inf
|| $mod->is_zero());
# check exponent for valid values
if ($exp->{sign} =~ /\w/) {
# i.e., if it's NaN, +inf, or -inf...
return $num->bnan();
}
$num->bmodinv ($mod) if ($exp->{sign} eq '-');
# check num for valid values (also NaN if there was no inverse but $exp < 0)
return $num->bnan() if $num->{sign} !~ /^[+-]$/;
# $mod is positive, sign on $exp is ignored, result also positive
# XXX TODO: speed it up when all three numbers are integers
$num->bpow($exp)->bmod($mod);
}
sub bpow {
# (BFLOAT or num_str, BFLOAT or num_str) return BFLOAT
# compute power of two numbers, second arg is used as integer
# modifies first argument
# set up parameters
my ($class, $x, $y, $a, $p, $r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, $a, $p, $r) = objectify(2, @_);
}
return $x if $x -> modify('bpow');
# $x and/or $y is a NaN
return $x -> bnan() if $x -> is_nan() || $y -> is_nan();
# $x and/or $y is a +/-Inf
if ($x -> is_inf("-")) {
return $x -> bzero() if $y -> is_negative();
return $x -> bnan() if $y -> is_zero();
return $x if $y -> is_odd();
return $x -> bneg();
} elsif ($x -> is_inf("+")) {
return $x -> bzero() if $y -> is_negative();
return $x -> bnan() if $y -> is_zero();
return $x;
} elsif ($y -> is_inf("-")) {
return $x -> bnan() if $x -> is_one("-");
return $x -> binf("+") if $x > -1 && $x < 1;
return $x -> bone() if $x -> is_one("+");
return $x -> bzero();
} elsif ($y -> is_inf("+")) {
return $x -> bnan() if $x -> is_one("-");
return $x -> bzero() if $x > -1 && $x < 1;
return $x -> bone() if $x -> is_one("+");
return $x -> binf("+");
}
if ($x -> is_zero()) {
return $x -> bone() if $y -> is_zero();
return $x -> binf() if $y -> is_negative();
return $x;
}
# We don't support complex numbers, so upgrade or return NaN.
if ($x -> is_negative() && !$y -> is_int()) {
return $upgrade -> bpow($upgrade -> new($x), $y, $a, $p, $r)
if defined $upgrade;
return $x -> bnan();
}
if ($x -> is_one("+") || $y -> is_one()) {
return $x;
}
if ($x -> is_one("-")) {
return $x if $y -> is_odd();
return $x -> bneg();
}
return $x -> _pow($y, $a, $p, $r) if !$y -> is_int();
my $y1 = $y -> as_int()->{value}; # make MBI part
my $new_sign = '+';
$new_sign = $LIB -> _is_odd($y1) ? '-' : '+' if $x->{sign} ne '+';
# calculate $x->{_m} ** $y and $x->{_e} * $y separately (faster)
$x->{_m} = $LIB -> _pow($x->{_m}, $y1);
$x->{_e} = $LIB -> _mul($x->{_e}, $y1);
$x->{sign} = $new_sign;
$x -> bnorm();
# x ** (-y) = 1 / (x ** y)
if ($y->{sign} eq '-') {
# modify $x in place!
my $z = $x -> copy();
$x -> bone();
# round in one go (might ignore y's A!)
return scalar $x -> bdiv($z, $a, $p, $r);
}
$x -> round($a, $p, $r, $y);
}
sub blog {
# Return the logarithm of the operand. If a second operand is defined, that
# value is used as the base, otherwise the base is assumed to be Euler's
# constant.
my ($class, $x, $base, $a, $p, $r);
# Don't objectify the base, since an undefined base, as in $x->blog() or
# $x->blog(undef) signals that the base is Euler's number.
if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
# E.g., Math::BigFloat->blog(256, 2)
($class, $x, $base, $a, $p, $r) =
defined $_[2] ? objectify(2, @_) : objectify(1, @_);
} else {
# E.g., Math::BigFloat::blog(256, 2) or $x->blog(2)
($class, $x, $base, $a, $p, $r) =
defined $_[1] ? objectify(2, @_) : objectify(1, @_);
}
return $x if $x->modify('blog');
return $x -> bnan() if $x -> is_nan();
# 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);
# no rounding at all, so must use fallback
if (scalar @params == 0) {
# simulate old behaviour
$params[0] = $class->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
} else {
# the 4 below is empirical, and there might be cases where it is not
# enough...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
my $done = 0;
if (defined $base) {
$base = $class -> new($base) unless ref $base;
if ($base -> is_nan() || $base -> is_one()) {
$x -> bnan();
$done = 1;
} elsif ($base -> is_inf() || $base -> is_zero()) {
if ($x -> is_inf() || $x -> is_zero()) {
$x -> bnan();
} else {
$x -> bzero(@params);
}
$done = 1;
} elsif ($base -> is_negative()) { # -inf < base < 0
if ($x -> is_one()) { # x = 1
$x -> bzero(@params);
} elsif ($x == $base) {
$x -> bone('+', @params); # x = base
} else {
$x -> bnan(); # otherwise
}
$done = 1;
} elsif ($x == $base) {
$x -> bone('+', @params); # 0 < base && 0 < x < inf
$done = 1;
}
}
# We now know that the base is either undefined or positive and finite.
unless ($done) {
if ($x -> is_inf()) { # x = +/-inf
my $sign = defined $base && $base < 1 ? '-' : '+';
$x -> binf($sign);
$done = 1;
} elsif ($x -> is_neg()) { # -inf < x < 0
$x -> bnan();
$done = 1;
} elsif ($x -> is_one()) { # x = 1
$x -> bzero(@params);
$done = 1;
} elsif ($x -> is_zero()) { # x = 0
my $sign = defined $base && $base < 1 ? '+' : '-';
$x -> binf($sign);
$done = 1;
}
}
if ($done) {
if ($fallback) {
# clear a/p after round, since user did not request it
delete $x->{_a};
delete $x->{_p};
}
return $x;
}
# when user set globals, they would interfere with our calculation, so
# disable them and later re-enable them
no strict 'refs';
my $abr = "$class\::accuracy"; my $ab = $$abr; $$abr = undef;
my $pbr = "$class\::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;
local $Math::BigFloat::downgrade = undef;
# upgrade $x if $x is not a Math::BigFloat (handle BigInt input)
# XXX TODO: rebless!
if (!$x->isa('Math::BigFloat')) {
$x = Math::BigFloat->new($x);
$class = ref($x);
}
$done = 0;
# If the base is defined and an integer, try to calculate integer result
# first. This is very fast, and in case the real result was found, we can
# stop right here.
if (defined $base && $base->is_int() && $x->is_int()) {
my $xint = Math::BigInt -> new($x -> bdstr());
my $bint = Math::BigInt -> new($base -> bdstr());
$xint->blog($bint);
# if we found the exact result, we're done
if ($bint -> bpow($xint) == $x) {
my $xflt = Math::BigFloat -> new($xint -> bdstr());
$x->{sign} = $xflt->{sign};
$x->{_m} = $xflt->{_m};
$x->{_es} = $xflt->{_es};
$x->{_e} = $xflt->{_e};
$done = 1;
}
}
if ($done == 0) {
# First calculate the log to base e (using reduction by 10 and possibly
# also by 2):
$x->_log_10($scale);
# and if a different base was requested, convert it
if (defined $base) {
$base = Math::BigFloat->new($base)
unless $base->isa('Math::BigFloat');
# log_b(x) = ln(x) / ln(b), so compute ln(b)
my $base_log_e = $base->copy()->_log_10($scale);
$x->bdiv($base_log_e, $scale);
}
}
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x->bround($params[0], $params[2]); # then round accordingly
} else {
$x->bfround($params[1], $params[2]); # then round accordingly
}
if ($fallback) {
# clear a/p after round, since user did not request it
delete $x->{_a};
delete $x->{_p};
}
# restore globals
$$abr = $ab;
$$pbr = $pb;
$x;
}
sub bexp {
# Calculate e ** X (Euler's number to the power of X)
my ($class, $x, $a, $p, $r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bexp');
return $x->binf() if $x->{sign} eq '+inf';
return $x->bzero() 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);
# also takes care of the "error in _find_round_parameters?" case
return $x if $x->{sign} eq 'NaN';
# no rounding at all, so must use fallback
if (scalar @params == 0) {
# simulate old behaviour
$params[0] = $class->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
} else {
# the 4 below is empirical, and there might be cases where it's not
# enough ...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
return $x->bone(@params) if $x->is_zero();
if (!$x->isa('Math::BigFloat')) {
$x = Math::BigFloat->new($x);
$class = ref($x);
}
# when user set globals, they would interfere with our calculation, so
# disable them and later re-enable them
no strict 'refs';
my $abr = "$class\::accuracy"; my $ab = $$abr; $$abr = undef;
my $pbr = "$class\::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;
local $Math::BigFloat::downgrade = undef;
my $x_org = $x->copy();
# We use the following Taylor series:
# x x^2 x^3 x^4
# e = 1 + --- + --- + --- + --- ...
# 1! 2! 3! 4!
# The difference for each term is X and N, which would result in:
# 2 copy, 2 mul, 2 add, 1 inc, 1 div operations per term
# But it is faster to compute exp(1) and then raising it to the
# given power, esp. if $x is really big and an integer because:
# * The numerator is always 1, making the computation faster
# * the series converges faster in the case of x == 1
# * We can also easily check when we have reached our limit: when the
# term to be added is smaller than "1E$scale", we can stop - f.i.
# scale == 5, and we have 1/40320, then we stop since 1/40320 < 1E-5.
# * we can compute the *exact* result by simulating bigrat math:
# 1 1 gcd(3, 4) = 1 1*24 + 1*6 5
# - + - = ---------- = --
# 6 24 6*24 24
# We do not compute the gcd() here, but simple do:
# 1 1 1*24 + 1*6 30
# - + - = --------- = --
# 6 24 6*24 144
# In general:
# a c a*d + c*b and note that c is always 1 and d = (b*f)
# - + - = ---------
# b d b*d
# This leads to: which can be reduced by b to:
# a 1 a*b*f + b a*f + 1
# - + - = --------- = -------
# b b*f b*b*f b*f
# The first terms in the series are:
# 1 1 1 1 1 1 1 1 13700
# -- + -- + -- + -- + -- + --- + --- + ---- = -----
# 1 1 2 6 24 120 720 5040 5040
# Note that we cannot simply reduce 13700/5040 to 685/252, but must keep
# the numerator and the denominator!
if ($scale <= 75) {
# set $x directly from a cached string form
$x->{_m} = $LIB->_new("2718281828459045235360287471352662497757" .
"2470936999595749669676277240766303535476");
$x->{sign} = '+';
$x->{_es} = '-';
$x->{_e} = $LIB->_new(79);
} else {
# compute A and B so that e = A / B.
# After some terms we end up with this, so we use it as a starting point:
my $A = $LIB->_new("9093339520860578540197197" .
"0164779391644753259799242");
my $F = $LIB->_new(42);
my $step = 42;
# Compute how many steps we need to take to get $A and $B sufficiently big
my $steps = _len_to_steps($scale - 4);
# print STDERR "# Doing $steps steps for ", $scale-4, " digits\n";
while ($step++ <= $steps) {
# calculate $a * $f + 1
$A = $LIB->_mul($A, $F);
$A = $LIB->_inc($A);
# increment f
$F = $LIB->_inc($F);
}
# compute $B as factorial of $steps (this is faster than doing it manually)
my $B = $LIB->_fac($LIB->_new($steps));
# print "A ", $LIB->_str($A), "\nB ", $LIB->_str($B), "\n";
# compute A/B with $scale digits in the result (truncate, not round)
$A = $LIB->_lsft($A, $LIB->_new($scale), 10);
$A = $LIB->_div($A, $B);
$x->{_m} = $A;
$x->{sign} = '+';
$x->{_es} = '-';
$x->{_e} = $LIB->_new($scale);
}
# $x contains now an estimate of e, with some surplus digits, so we can round
if (!$x_org->is_one()) {
# Reduce size of fractional part, followup with integer power of two.
my $lshift = 0;
while ($lshift < 30 && $x_org->bacmp(2 << $lshift) > 0) {
$lshift++;
}
# Raise $x to the wanted power and round it.
if ($lshift == 0) {
$x->bpow($x_org, @params);
} else {
my($mul, $rescale) = (1 << $lshift, $scale+1+$lshift);
$x->bpow(scalar $x_org->bdiv($mul, $rescale), $rescale)->bpow($mul, @params);
}
} else {
# else just round the already computed result
delete $x->{_a};
delete $x->{_p};
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x->bround($params[0], $params[2]); # then round accordingly
} else {
$x->bfround($params[1], $params[2]); # then round accordingly
}
}
if ($fallback) {
# clear a/p after round, since user did not request it
delete $x->{_a};
delete $x->{_p};
}
# restore globals
$$abr = $ab;
$$pbr = $pb;
$x; # return modified $x
}
sub bnok {
# Calculate n over k (binomial coefficient or "choose" function) as integer.
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x->modify('bnok');
return $x->bnan() if $x->is_nan() || $y->is_nan();
return $x->bnan() if (($x->is_finite() && !$x->is_int()) ||
($y->is_finite() && !$y->is_int()));
my $xint = Math::BigInt -> new($x -> bsstr());
my $yint = Math::BigInt -> new($y -> bsstr());
$xint -> bnok($yint);
my $xflt = Math::BigFloat -> new($xint);
$x->{_m} = $xflt->{_m};
$x->{_e} = $xflt->{_e};
$x->{_es} = $xflt->{_es};
$x->{sign} = $xflt->{sign};
return $x;
}
sub bsin {
# Calculate a sinus of x.
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# taylor: x^3 x^5 x^7 x^9
# sin = x - --- + --- - --- + --- ...
# 3! 5! 7! 9!
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my ($scale, @params);
($x, @params) = $x->_find_round_parameters(@r);
# constant object or error in _find_round_parameters?
return $x if $x->modify('bsin') || $x->is_nan();
return $x->bnan() if $x->is_inf();
return $x->bzero(@r) if $x->is_zero();
# no rounding at all, so must use fallback
if (scalar @params == 0) {
# simulate old behaviour
$params[0] = $class->div_scale(); # and round to it as accuracy
$params[1] = undef; # disable P
$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 {
# the 4 below is empirical, and there might be cases where it is not
# enough...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
# when user set globals, they would interfere with our calculation, so
# disable them and later re-enable them
no strict 'refs';
my $abr = "$class\::accuracy"; my $ab = $$abr; $$abr = undef;
my $pbr = "$class\::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 $over = $x * $x; # X ^ 2
my $x2 = $over->copy(); # X ^ 2; difference between terms
$over->bmul($x); # X ^ 3 as starting value
my $sign = 1; # start with -=
my $below = $class->new(6); my $factorial = $class->new(4);
delete $x->{_a};
delete $x->{_p};
my $limit = $class->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:
my $next = $over->copy()->bdiv($below, $scale);
last if $next->bacmp($limit) <= 0;
if ($sign == 0) {
$x->badd($next);
} else {
$x->bsub($next);
}
$sign = 1-$sign; # alternate
# calculate things for the next term
$over->bmul($x2); # $x*$x
$below->bmul($factorial); $factorial->binc(); # n*(n+1)
$below->bmul($factorial); $factorial->binc(); # n*(n+1)
}
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x->bround($params[0], $params[2]); # then round accordingly
} else {
$x->bfround($params[1], $params[2]); # then round accordingly
}
if ($fallback) {
# clear a/p after round, since user did not request it
delete $x->{_a};
delete $x->{_p};
}
# restore globals
$$abr = $ab;
$$pbr = $pb;
$x;
}
sub bcos {
# Calculate a cosinus of x.
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Taylor: x^2 x^4 x^6 x^8
# cos = 1 - --- + --- - --- + --- ...
# 2! 4! 6! 8!
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my ($scale, @params);
($x, @params) = $x->_find_round_parameters(@r);
# constant object or error in _find_round_parameters?
return $x if $x->modify('bcos') || $x->is_nan();
return $x->bnan() if $x->is_inf();
return $x->bone(@r) if $x->is_zero();
# no rounding at all, so must use fallback
if (scalar @params == 0) {
# simulate old behaviour
$params[0] = $class->div_scale(); # and round to it as accuracy
$params[1] = undef; # disable P
$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 {
# the 4 below is empirical, and there might be cases where it is not
# enough...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
# when user set globals, they would interfere with our calculation, so
# disable them and later re-enable them
no strict 'refs';
my $abr = "$class\::accuracy"; my $ab = $$abr; $$abr = undef;
my $pbr = "$class\::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 $over = $x * $x; # X ^ 2
my $x2 = $over->copy(); # X ^ 2; difference between terms
my $sign = 1; # start with -=
my $below = $class->new(2);
my $factorial = $class->new(3);
$x->bone();
delete $x->{_a};
delete $x->{_p};
my $limit = $class->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:
my $next = $over->copy()->bdiv($below, $scale);
last if $next->bacmp($limit) <= 0;
if ($sign == 0) {
$x->badd($next);
} else {
$x->bsub($next);
}
$sign = 1-$sign; # alternate
# calculate things for the next term
$over->bmul($x2); # $x*$x
$below->bmul($factorial); $factorial->binc(); # n*(n+1)
$below->bmul($factorial); $factorial->binc(); # n*(n+1)
}
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x->bround($params[0], $params[2]); # then round accordingly
} else {
$x->bfround($params[1], $params[2]); # then round accordingly
}
if ($fallback) {
# clear a/p after round, since user did not request it
delete $x->{_a};
delete $x->{_p};
}
# restore globals
$$abr = $ab;
$$pbr = $pb;
$x;
}
sub batan {
# Calculate a arcus tangens of x.
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
my (@r) = @_;
# taylor: x^3 x^5 x^7 x^9
# atan = x - --- + --- - --- + --- ...
# 3 5 7 9
# We need to limit the accuracy to protect against overflow.
my $fallback = 0;
my ($scale, @params);
($self, @params) = $self->_find_round_parameters(@r);
# Constant object or error in _find_round_parameters?
return $self if $self->modify('batan') || $self->is_nan();
if ($self->{sign} =~ /^[+-]inf\z/) {
# +inf result is PI/2
# -inf result is -PI/2
# calculate PI/2
my $pi = $class->bpi(@r);
# modify $self in place
$self->{_m} = $pi->{_m};
$self->{_e} = $pi->{_e};
$self->{_es} = $pi->{_es};
# -y => -PI/2, +y => PI/2
$self->{sign} = substr($self->{sign}, 0, 1); # "+inf" => "+"
$self -> {_m} = $LIB->_div($self->{_m}, $LIB->_new(2));
return $self;
}
return $self->bzero(@r) if $self->is_zero();
# no rounding at all, so must use fallback
if (scalar @params == 0) {
# simulate old behaviour
$params[0] = $class->div_scale(); # and round to it as accuracy
$params[1] = undef; # disable P
$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 {
# the 4 below is empirical, and there might be cases where it is not
# enough...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
# 1 or -1 => PI/4
# inlined is_one() && is_one('-')
if ($LIB->_is_one($self->{_m}) && $LIB->_is_zero($self->{_e})) {
my $pi = $class->bpi($scale - 3);
# modify $self in place
$self->{_m} = $pi->{_m};
$self->{_e} = $pi->{_e};
$self->{_es} = $pi->{_es};
# leave the sign of $self alone (+1 => +PI/4, -1 => -PI/4)
$self->{_m} = $LIB->_div($self->{_m}, $LIB->_new(4));
return $self;
}
# This series is only valid if -1 < x < 1, so for other x we need to
# calculate PI/2 - atan(1/x):
my $pi = undef;
if ($self->bacmp($self->copy()->bone) >= 0) {
# calculate PI/2
$pi = $class->bpi($scale - 3);
$pi->{_m} = $LIB->_div($pi->{_m}, $LIB->_new(2));
# calculate 1/$self:
my $self_copy = $self->copy();
# modify $self in place
$self->bone();
$self->bdiv($self_copy, $scale);
}
my $fmul = 1;
foreach (0 .. int($scale / 20)) {
$fmul *= 2;
$self->bdiv($self->copy()->bmul($self)->binc->bsqrt($scale + 4)->binc, $scale + 4);
}
# When user set globals, they would interfere with our calculation, so
# disable them and later re-enable them.
no strict 'refs';
my $abr = "$class\::accuracy"; my $ab = $$abr; $$abr = undef;
my $pbr = "$class\::precision"; my $pb = $$pbr; $$pbr = undef;
# We also need to disable any set A or P on $self (_find_round_parameters
# took them already into account), since these would interfere, too
delete $self->{_a};
delete $self->{_p};
# Need to disable $upgrade in BigInt, to avoid deep recursion.
local $Math::BigInt::upgrade = undef;
my $over = $self * $self; # X ^ 2
my $self2 = $over->copy(); # X ^ 2; difference between terms
$over->bmul($self); # X ^ 3 as starting value
my $sign = 1; # start with -=
my $below = $class->new(3);
my $two = $class->new(2);
delete $self->{_a};
delete $self->{_p};
my $limit = $class->new("1E-". ($scale-1));
#my $steps = 0;
while (1) {
# 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:
my $next = $over->copy()->bdiv($below, $scale);
last if $next->bacmp($limit) <= 0;
if ($sign == 0) {
$self->badd($next);
} else {
$self->bsub($next);
}
$sign = 1-$sign; # alternatex
# calculate things for the next term
$over->bmul($self2); # $self*$self
$below->badd($two); # n += 2
}
$self->bmul($fmul);
if (defined $pi) {
my $self_copy = $self->copy();
# modify $self in place
$self->{_m} = $pi->{_m};
$self->{_e} = $pi->{_e};
$self->{_es} = $pi->{_es};
# PI/2 - $self
$self->bsub($self_copy);
}
# Shortcut to not run through _find_round_parameters again.
if (defined $params[0]) {
$self->bround($params[0], $params[2]); # then round accordingly
} else {
$self->bfround($params[1], $params[2]); # then round accordingly
}
if ($fallback) {
# Clear a/p after round, since user did not request it.
delete $self->{_a};
delete $self->{_p};
}
# restore globals
$$abr = $ab;
$$pbr = $pb;
$self;
}
sub batan2 {
# $y -> batan2($x) returns the arcus tangens of $y / $x.
# Set up parameters.
my ($class, $y, $x, @r) = (ref($_[0]), @_);
# Objectify is costly, so avoid it if we can.
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $y, $x, @r) = objectify(2, @_);
}
# Quick exit if $y is read-only.
return $y if $y -> modify('batan2');
# Handle all NaN cases.
return $y -> bnan() if $x->{sign} eq $nan || $y->{sign} eq $nan;
# We need to limit the accuracy to protect against overflow.
my $fallback = 0;
my ($scale, @params);
($y, @params) = $y -> _find_round_parameters(@r);
# Error in _find_round_parameters?
return $y if $y->is_nan();
# No rounding at all, so must use fallback.
if (scalar @params == 0) {
# Simulate old behaviour
$params[0] = $class -> div_scale(); # and round to it as accuracy
$params[1] = undef; # disable P
$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 {
# The 4 below is empirical, and there might be cases where it is not
# enough ...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
if ($x -> is_inf("+")) { # x = inf
if ($y -> is_inf("+")) { # y = inf
$y -> bpi($scale) -> bmul("0.25"); # pi/4
} elsif ($y -> is_inf("-")) { # y = -inf
$y -> bpi($scale) -> bmul("-0.25"); # -pi/4
} else { # -inf < y < inf
return $y -> bzero(@r); # 0
}
} elsif ($x -> is_inf("-")) { # x = -inf
if ($y -> is_inf("+")) { # y = inf
$y -> bpi($scale) -> bmul("0.75"); # 3/4 pi
} elsif ($y -> is_inf("-")) { # y = -inf
$y -> bpi($scale) -> bmul("-0.75"); # -3/4 pi
} elsif ($y >= 0) { # y >= 0
$y -> bpi($scale); # pi
} else { # y < 0
$y -> bpi($scale) -> bneg(); # -pi
}
} elsif ($x > 0) { # 0 < x < inf
if ($y -> is_inf("+")) { # y = inf
$y -> bpi($scale) -> bmul("0.5"); # pi/2
} elsif ($y -> is_inf("-")) { # y = -inf
$y -> bpi($scale) -> bmul("-0.5"); # -pi/2
} else { # -inf < y < inf
$y -> bdiv($x, $scale) -> batan($scale); # atan(y/x)
}
} elsif ($x < 0) { # -inf < x < 0
my $pi = $class -> bpi($scale);
if ($y >= 0) { # y >= 0
$y -> bdiv($x, $scale) -> batan() # atan(y/x) + pi
-> badd($pi);
} else { # y < 0
$y -> bdiv($x, $scale) -> batan() # atan(y/x) - pi
-> bsub($pi);
}
} else { # x = 0
if ($y > 0) { # y > 0
$y -> bpi($scale) -> bmul("0.5"); # pi/2
} elsif ($y < 0) { # y < 0
$y -> bpi($scale) -> bmul("-0.5"); # -pi/2
} else { # y = 0
return $y -> bzero(@r); # 0
}
}
$y -> round(@r);
if ($fallback) {
delete $y->{_a};
delete $y->{_p};
}
return $y;
}
##############################################################################
sub bsqrt {
# calculate square root
my ($class, $x, $a, $p, $r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bsqrt');
return $x->bnan() if $x->{sign} !~ /^\+/; # NaN, -inf or < 0
return $x if $x->{sign} eq '+inf'; # sqrt(inf) == inf
return $x->round($a, $p, $r) if $x->is_zero() || $x->is_one();
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my (@params, $scale);
($x, @params) = $x->_find_round_parameters($a, $p, $r);
return $x if $x->is_nan(); # error in _find_round_parameters?
# no rounding at all, so must use fallback
if (scalar @params == 0) {
# simulate old behaviour
$params[0] = $class->div_scale(); # and round to it as accuracy
$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
} else {
# the 4 below is empirical, and there might be cases where it is not
# enough...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
# when user set globals, they would interfere with our calculation, so
# disable them and later re-enable them
no strict 'refs';
my $abr = "$class\::accuracy"; my $ab = $$abr; $$abr = undef;
my $pbr = "$class\::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; # should be really parent class vs MBI
my $i = $LIB->_copy($x->{_m});
$i = $LIB->_lsft($i, $x->{_e}, 10) unless $LIB->_is_zero($x->{_e});
my $xas = Math::BigInt->bzero();
$xas->{value} = $i;
my $gs = $xas->copy()->bsqrt(); # some guess
if (($x->{_es} 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?
{
# exact result, copy result over to keep $x
$x->{_m} = $gs->{value};
$x->{_e} = $LIB->_zero();
$x->{_es} = '+';
$x->bnorm();
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x->bround($params[0], $params[2]); # then round accordingly
} else {
$x->bfround($params[1], $params[2]); # then round accordingly
}
if ($fallback) {
# clear a/p after round, since user did not request it
delete $x->{_a};
delete $x->{_p};
}
# re-enable A and P, upgrade is taken care of by "local"
${"$class\::accuracy"} = $ab;
${"$class\::precision"} = $pb;
return $x;
}
# sqrt(2) = 1.4 because sqrt(2*100) = 1.4*10; so we can increase the accuracy
# of the result by multiplying the input by 100 and then divide the integer
# result of sqrt(input) by 10. Rounding afterwards returns the real result.
# The following steps will transform 123.456 (in $x) into 123456 (in $y1)
my $y1 = $LIB->_copy($x->{_m});
my $length = $LIB->_len($y1);
# Now calculate how many digits the result of sqrt(y1) would have
my $digits = int($length / 2);
# But we need at least $scale digits, so calculate how many are missing
my $shift = $scale - $digits;
# This happens if the input had enough digits
# (we take care of integer guesses above)
$shift = 0 if $shift < 0;
# Multiply in steps of 100, by shifting left two times the "missing" digits
my $s2 = $shift * 2;
# We now make sure that $y1 has the same odd or even number of digits than
# $x had. So when _e of $x is odd, we must shift $y1 by one digit left,
# because we always must multiply by steps of 100 (sqrt(100) is 10) and not
# steps of 10. The length of $x does not count, since an even or odd number
# of digits before the dot is not changed by adding an even number of digits
# after the dot (the result is still odd or even digits long).
$s2++ if $LIB->_is_odd($x->{_e});
$y1 = $LIB->_lsft($y1, $LIB->_new($s2), 10);
# now take the square root and truncate to integer
$y1 = $LIB->_sqrt($y1);
# By "shifting" $y1 right (by creating a negative _e) we calculate the final
# result, which is than later rounded to the desired scale.
# calculate how many zeros $x had after the '.' (or before it, depending
# on sign of $dat, the result should have half as many:
my $dat = $LIB->_num($x->{_e});
$dat = -$dat if $x->{_es} eq '-';
$dat += $length;
if ($dat > 0) {
# no zeros after the dot (e.g. 1.23, 0.49 etc)
# preserve half as many digits before the dot than the input had
# (but round this "up")
$dat = int(($dat+1)/2);
} else {
$dat = int(($dat)/2);
}
$dat -= $LIB->_len($y1);
if ($dat < 0) {
$dat = abs($dat);
$x->{_e} = $LIB->_new($dat);
$x->{_es} = '-';
} else {
$x->{_e} = $LIB->_new($dat);
$x->{_es} = '+';
}
$x->{_m} = $y1;
$x->bnorm();
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x->bround($params[0], $params[2]); # then round accordingly
} else {
$x->bfround($params[1], $params[2]); # then round accordingly
}
if ($fallback) {
# clear a/p after round, since user did not request it
delete $x->{_a};
delete $x->{_p};
}
# restore globals
$$abr = $ab;
$$pbr = $pb;
$x;
}
sub broot {
# calculate $y'th root of $x
# set up parameters
my ($class, $x, $y, $a, $p, $r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, $a, $p, $r) = objectify(2, @_);
}
return $x if $x->modify('broot');
# NaN handling: $x ** 1/0, x or y NaN, or y inf/-inf or y == 0
return $x->bnan() if $x->{sign} !~ /^\+/ || $y->is_zero() ||
$y->{sign} !~ /^\+$/;
return $x if $x->is_zero() || $x->is_one() || $x->is_inf() || $y->is_one();
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my (@params, $scale);
($x, @params) = $x->_find_round_parameters($a, $p, $r);
return $x if $x->is_nan(); # error in _find_round_parameters?
# no rounding at all, so must use fallback
if (scalar @params == 0) {
# simulate old behaviour
$params[0] = $class->div_scale(); # and round to it as accuracy
$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
} else {
# the 4 below is empirical, and there might be cases where it is not
# enough...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
# when user set globals, they would interfere with our calculation, so
# disable them and later re-enable them
no strict 'refs';
my $abr = "$class\::accuracy"; my $ab = $$abr; $$abr = undef;
my $pbr = "$class\::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; # should be really parent class vs MBI
# remember sign and make $x positive, since -4 ** (1/2) => -2
my $sign = 0;
$sign = 1 if $x->{sign} eq '-';
$x->{sign} = '+';
my $is_two = 0;
if ($y->isa('Math::BigFloat')) {
$is_two = ($y->{sign} eq '+' && $LIB->_is_two($y->{_m}) && $LIB->_is_zero($y->{_e}));
} else {
$is_two = ($y == 2);
}
# normal square root if $y == 2:
if ($is_two) {
$x->bsqrt($scale+4);
} elsif ($y->is_one('-')) {
# $x ** -1 => 1/$x
my $u = $class->bone()->bdiv($x, $scale);
# copy private parts over
$x->{_m} = $u->{_m};
$x->{_e} = $u->{_e};
$x->{_es} = $u->{_es};
} else {
# calculate the broot() as integer result first, and if it fits, return
# it rightaway (but only if $x and $y are integer):
my $done = 0; # not yet
if ($y->is_int() && $x->is_int()) {
my $i = $LIB->_copy($x->{_m});
$i = $LIB->_lsft($i, $x->{_e}, 10) unless $LIB->_is_zero($x->{_e});
my $int = Math::BigInt->bzero();
$int->{value} = $i;
$int->broot($y->as_number());
# if ($exact)
if ($int->copy()->bpow($y) == $x) {
# found result, return it
$x->{_m} = $int->{value};
$x->{_e} = $LIB->_zero();
$x->{_es} = '+';
$x->bnorm();
$done = 1;
}
}
if ($done == 0) {
my $u = $class->bone()->bdiv($y, $scale+4);
delete $u->{_a}; delete $u->{_p}; # otherwise it conflicts
$x->bpow($u, $scale+4); # el cheapo
}
}
$x->bneg() if $sign == 1;
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x->bround($params[0], $params[2]); # then round accordingly
} else {
$x->bfround($params[1], $params[2]); # then round accordingly
}
if ($fallback) {
# clear a/p after round, since user did not request it
delete $x->{_a};
delete $x->{_p};
}
# restore globals
$$abr = $ab;
$$pbr = $pb;
$x;
}
sub bfac {
# (BFLOAT or num_str, BFLOAT or num_str) return BFLOAT
# compute factorial number, modifies first argument
# set up parameters
my ($class, $x, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
($class, $x, @r) = objectify(1, @_) if !ref($x);
# inf => inf
return $x if $x->modify('bfac') || $x->{sign} eq '+inf';
return $x->bnan()
if (($x->{sign} ne '+') || # inf, NaN, <0 etc => NaN
($x->{_es} ne '+')); # digits after dot?
if (! $LIB->_is_zero($x->{_e})) {
$x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10); # change 12e1 to 120e0
$x->{_e} = $LIB->_zero(); # normalize
$x->{_es} = '+';
}
$x->{_m} = $LIB->_fac($x->{_m}); # calculate factorial
$x->bnorm()->round(@r); # norm again and round result
}
sub bdfac {
# compute double factorial
# set up parameters
my ($class, $x, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
($class, $x, @r) = objectify(1, @_) if !ref($x);
# inf => inf
return $x if $x->modify('bdfac') || $x->{sign} eq '+inf';
return $x->bnan() if ($x->is_nan() ||
$x->{_es} ne '+'); # digits after dot?
return $x->bnan() if $x <= -2;
return $x->bone() if $x <= 1;
croak("bdfac() requires a newer version of the $LIB library.")
unless $LIB->can('_dfac');
if (! $LIB->_is_zero($x->{_e})) {
$x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10); # change 12e1 to 120e0
$x->{_e} = $LIB->_zero(); # normalize
$x->{_es} = '+';
}
$x->{_m} = $LIB->_dfac($x->{_m}); # calculate factorial
$x->bnorm()->round(@r); # norm again and round result
}
sub btfac {
# compute triple factorial
# set up parameters
my ($class, $x, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
($class, $x, @r) = objectify(1, @_) if !ref($x);
# inf => inf
return $x if $x->modify('btfac') || $x->{sign} eq '+inf';
return $x->bnan() if ($x->is_nan() ||
$x->{_es} ne '+'); # digits after dot?
my $k = $class -> new("3");
return $x->bnan() if $x <= -$k;
my $one = $class -> bone();
return $x->bone() if $x <= $one;
my $f = $x -> copy();
while ($f -> bsub($k) > $one) {
$x -> bmul($f);
}
$x->round(@r);
}
sub bmfac {
my ($class, $x, $k, @r) = objectify(2, @_);
# inf => inf
return $x if $x->modify('bmfac') || $x->{sign} eq '+inf';
return $x->bnan() if ($x->is_nan() || $k->is_nan() ||
$k < 1 || $x <= -$k ||
$x->{_es} ne '+' || $k->{_es} ne '+');
return $x->bnan() if $x <= -$k;
my $one = $class -> bone();
return $x->bone() if $x <= $one;
my $f = $x -> copy();
while ($f -> bsub($k) > $one) {
$x -> bmul($f);
}
$x->round(@r);
}
sub blsft {
# shift left by $y (multiply by $b ** $y)
# set up parameters
my ($class, $x, $y, $b, $a, $p, $r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, $b, $a, $p, $r) = objectify(2, @_);
}
return $x if $x -> modify('blsft');
return $x if $x -> {sign} !~ /^[+-]$/; # nan, +inf, -inf
$b = 2 if !defined $b;
$b = $class -> new($b) unless ref($b) && $b -> isa($class);
return $x -> bnan() if $x -> is_nan() || $y -> is_nan() || $b -> is_nan();
# shift by a negative amount?
return $x -> brsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
$x -> bmul($b -> bpow($y), $a, $p, $r, $y);
}
sub brsft {
# shift right by $y (divide $b ** $y)
# set up parameters
my ($class, $x, $y, $b, $a, $p, $r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, $b, $a, $p, $r) = objectify(2, @_);
}
return $x if $x -> modify('brsft');
return $x if $x -> {sign} !~ /^[+-]$/; # nan, +inf, -inf
$b = 2 if !defined $b;
$b = $class -> new($b) unless ref($b) && $b -> isa($class);
return $x -> bnan() if $x -> is_nan() || $y -> is_nan() || $b -> is_nan();
# shift by a negative amount?
return $x -> blsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
# the following call to bdiv() will return either quotient (scalar context)
# or quotient and remainder (list context).
$x -> bdiv($b -> bpow($y), $a, $p, $r, $y);
}
###############################################################################
# Bitwise methods
###############################################################################
sub band {
my $x = shift;
my $xref = ref($x);
my $class = $xref || $x;
croak 'band() is an instance method, not a class method' unless $xref;
croak 'Not enough arguments for band()' if @_ < 1;
return if $x -> modify('band');
my $y = shift;
$y = $class -> new($y) unless ref($y);
my @r = @_;
my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
$xtmp -> band($y);
$xtmp = $class -> new($xtmp); # back to Math::BigFloat
$x -> {sign} = $xtmp -> {sign};
$x -> {_m} = $xtmp -> {_m};
$x -> {_es} = $xtmp -> {_es};
$x -> {_e} = $xtmp -> {_e};
return $x -> round(@r);
}
sub bior {
my $x = shift;
my $xref = ref($x);
my $class = $xref || $x;
croak 'bior() is an instance method, not a class method' unless $xref;
croak 'Not enough arguments for bior()' if @_ < 1;
return if $x -> modify('bior');
my $y = shift;
$y = $class -> new($y) unless ref($y);
my @r = @_;
my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
$xtmp -> bior($y);
$xtmp = $class -> new($xtmp); # back to Math::BigFloat
$x -> {sign} = $xtmp -> {sign};
$x -> {_m} = $xtmp -> {_m};
$x -> {_es} = $xtmp -> {_es};
$x -> {_e} = $xtmp -> {_e};
return $x -> round(@r);
}
sub bxor {
my $x = shift;
my $xref = ref($x);
my $class = $xref || $x;
croak 'bxor() is an instance method, not a class method' unless $xref;
croak 'Not enough arguments for bxor()' if @_ < 1;
return if $x -> modify('bxor');
my $y = shift;
$y = $class -> new($y) unless ref($y);
my @r = @_;
my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
$xtmp -> bxor($y);
$xtmp = $class -> new($xtmp); # back to Math::BigFloat
$x -> {sign} = $xtmp -> {sign};
$x -> {_m} = $xtmp -> {_m};
$x -> {_es} = $xtmp -> {_es};
$x -> {_e} = $xtmp -> {_e};
return $x -> round(@r);
}
sub bnot {
my $x = shift;
my $xref = ref($x);
my $class = $xref || $x;
croak 'bnot() is an instance method, not a class method' unless $xref;
return if $x -> modify('bnot');
my @r = @_;
my $xtmp = Math::BigInt -> new($x -> bint()); # to Math::BigInt
$xtmp -> bnot();
$xtmp = $class -> new($xtmp); # back to Math::BigFloat
$x -> {sign} = $xtmp -> {sign};
$x -> {_m} = $xtmp -> {_m};
$x -> {_es} = $xtmp -> {_es};
$x -> {_e} = $xtmp -> {_e};
return $x -> round(@r);
}
###############################################################################
# Rounding methods
###############################################################################
sub bround {
# accuracy: preserve $N digits, and overwrite the rest with 0's
my $x = shift;
my $class = ref($x) || $x;
$x = $class->new(shift) if !ref($x);
if (($_[0] || 0) < 0) {
croak('bround() needs positive accuracy');
}
my ($scale, $mode) = $x->_scale_a(@_);
return $x if !defined $scale || $x->modify('bround'); # no-op
# scale is now either $x->{_a}, $accuracy, or the user parameter
# test whether $x already has lower accuracy, do nothing in this case
# but do round if the accuracy is the same, since a math operation might
# want to round a number with A=5 to 5 digits afterwards again
return $x if defined $x->{_a} && $x->{_a} < $scale;
# scale < 0 makes no sense
# scale == 0 => keep all digits
# never round a +-inf, NaN
return $x if ($scale <= 0) || $x->{sign} !~ /^[+-]$/;
# 1: never round a 0
# 2: if we should keep more digits than the mantissa has, do nothing
if ($x->is_zero() || $LIB->_len($x->{_m}) <= $scale) {
$x->{_a} = $scale if !defined $x->{_a} || $x->{_a} > $scale;
return $x;
}
# pass sign to bround for '+inf' and '-inf' rounding modes
my $m = bless { sign => $x->{sign}, value => $x->{_m} }, 'Math::BigInt';
$m->bround($scale, $mode); # round mantissa
$x->{_m} = $m->{value}; # get our mantissa back
$x->{_a} = $scale; # remember rounding
delete $x->{_p}; # and clear P
$x->bnorm(); # del trailing zeros gen. by bround()
}
sub bfround {
# precision: round to the $Nth digit left (+$n) or right (-$n) from the '.'
# $n == 0 means round to integer
# expects and returns normalized numbers!
my $x = shift;
my $class = ref($x) || $x;
$x = $class->new(shift) if !ref($x);
my ($scale, $mode) = $x->_scale_p(@_);
return $x if !defined $scale || $x->modify('bfround'); # no-op
# never round a 0, +-inf, NaN
if ($x->is_zero()) {
$x->{_p} = $scale if !defined $x->{_p} || $x->{_p} < $scale; # -3 < -2
return $x;
}
return $x if $x->{sign} !~ /^[+-]$/;
# don't round if x already has lower precision
return $x if (defined $x->{_p} && $x->{_p} < 0 && $scale < $x->{_p});
$x->{_p} = $scale; # remember round in any case
delete $x->{_a}; # and clear A
if ($scale < 0) {
# round right from the '.'
return $x if $x->{_es} eq '+'; # e >= 0 => nothing to round
$scale = -$scale; # positive for simplicity
my $len = $LIB->_len($x->{_m}); # length of mantissa
# the following poses a restriction on _e, but if _e is bigger than a
# scalar, you got other problems (memory etc) anyway
my $dad = -(0+ ($x->{_es}.$LIB->_num($x->{_e}))); # digits after dot
my $zad = 0; # zeros after dot
$zad = $dad - $len if (-$dad < -$len); # for 0.00..00xxx style
# print "scale $scale dad $dad zad $zad len $len\n";
# number bsstr len zad dad
# 0.123 123e-3 3 0 3
# 0.0123 123e-4 3 1 4
# 0.001 1e-3 1 2 3
# 1.23 123e-2 3 0 2
# 1.2345 12345e-4 5 0 4
# do not round after/right of the $dad
return $x if $scale > $dad; # 0.123, scale >= 3 => exit
# round to zero if rounding inside the $zad, but not for last zero like:
# 0.0065, scale -2, round last '0' with following '65' (scale == zad case)
return $x->bzero() if $scale < $zad;
if ($scale == $zad) # for 0.006, scale -3 and trunc
{
$scale = -$len;
} else {
# adjust round-point to be inside mantissa
if ($zad != 0) {
$scale = $scale-$zad;
} else {
my $dbd = $len - $dad;
$dbd = 0 if $dbd < 0; # digits before dot
$scale = $dbd+$scale;
}
}
} else {
# round left from the '.'
# 123 => 100 means length(123) = 3 - $scale (2) => 1
my $dbt = $LIB->_len($x->{_m});
# digits before dot
my $dbd = $dbt + ($x->{_es} . $LIB->_num($x->{_e}));
# should be the same, so treat it as this
$scale = 1 if $scale == 0;
# shortcut if already integer
return $x if $scale == 1 && $dbt <= $dbd;
# maximum digits before dot
++$dbd;
if ($scale > $dbd) {
# not enough digits before dot, so round to zero
return $x->bzero;
} elsif ($scale == $dbd) {
# maximum
$scale = -$dbt;
} else {
$scale = $dbd - $scale;
}
}
# pass sign to bround for rounding modes '+inf' and '-inf'
my $m = bless { sign => $x->{sign}, value => $x->{_m} }, 'Math::BigInt';
$m->bround($scale, $mode);
$x->{_m} = $m->{value}; # get our mantissa back
$x->bnorm();
}
sub bfloor {
# round towards minus infinity
my ($class, $x, $a, $p, $r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bfloor');
return $x if $x->{sign} !~ /^[+-]$/; # nan, +inf, -inf
# if $x has digits after dot
if ($x->{_es} eq '-') {
$x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10); # cut off digits after dot
$x->{_e} = $LIB->_zero(); # trunc/norm
$x->{_es} = '+'; # abs e
$x->{_m} = $LIB->_inc($x->{_m}) if $x->{sign} eq '-'; # increment if negative
}
$x->round($a, $p, $r);
}
sub bceil {
# round towards plus infinity
my ($class, $x, $a, $p, $r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bceil');
return $x if $x->{sign} !~ /^[+-]$/; # nan, +inf, -inf
# if $x has digits after dot
if ($x->{_es} eq '-') {
$x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10); # cut off digits after dot
$x->{_e} = $LIB->_zero(); # trunc/norm
$x->{_es} = '+'; # abs e
if ($x->{sign} eq '+') {
$x->{_m} = $LIB->_inc($x->{_m}); # increment if positive
} else {
$x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # avoid -0
}
}
$x->round($a, $p, $r);
}
sub bint {
# round towards zero
my ($class, $x, $a, $p, $r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bint');
return $x if $x->{sign} !~ /^[+-]$/; # nan, +inf, -inf
# if $x has digits after the decimal point
if ($x->{_es} eq '-') {
$x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10); # cut off digits after dot
$x->{_e} = $LIB->_zero(); # truncate/normalize
$x->{_es} = '+'; # abs e
$x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # avoid -0
}
$x->round($a, $p, $r);
}
###############################################################################
# Other mathematical methods
###############################################################################
sub bgcd {
# (BINT or num_str, BINT or num_str) return BINT
# does not modify arguments, but returns new object
unshift @_, __PACKAGE__
unless ref($_[0]) || $_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i;
my ($class, @args) = objectify(0, @_);
my $x = shift @args;
$x = ref($x) && $x -> isa($class) ? $x -> copy() : $class -> new($x);
return $class->bnan() unless $x -> is_int();
while (@args) {
my $y = shift @args;
$y = $class->new($y) unless ref($y) && $y -> isa($class);
return $class->bnan() unless $y -> is_int();
# greatest common divisor
while (! $y->is_zero()) {
($x, $y) = ($y->copy(), $x->copy()->bmod($y));
}
last if $x -> is_one();
}
return $x -> babs();
}
sub blcm {
# (BFLOAT or num_str, BFLOAT or num_str) return BFLOAT
# does not modify arguments, but returns new object
# Least Common Multiple
unshift @_, __PACKAGE__
unless ref($_[0]) || $_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i;
my ($class, @args) = objectify(0, @_);
my $x = shift @args;
$x = ref($x) && $x -> isa($class) ? $x -> copy() : $class -> new($x);
return $class->bnan() if $x->{sign} !~ /^[+-]$/; # x NaN?
while (@args) {
my $y = shift @args;
$y = $class -> new($y) unless ref($y) && $y -> isa($class);
return $x->bnan() unless $y -> is_int();
my $gcd = $x -> bgcd($y);
$x -> bdiv($gcd) -> bmul($y);
}
return $x -> babs();
}
###############################################################################
# Object property methods
###############################################################################
sub length {
my $x = shift;
my $class = ref($x) || $x;
$x = $class->new(shift) unless ref($x);
return 1 if $LIB->_is_zero($x->{_m});
my $len = $LIB->_len($x->{_m});
$len += $LIB->_num($x->{_e}) if $x->{_es} eq '+';
if (wantarray()) {
my $t = 0;
$t = $LIB->_num($x->{_e}) if $x->{_es} eq '-';
return ($len, $t);
}
$len;
}
sub mantissa {
# return a copy of the mantissa
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
if ($x->{sign} !~ /^[+-]$/) {
my $s = $x->{sign};
$s =~ s/^\+//;
return Math::BigInt->new($s, undef, undef); # -inf, +inf => +inf
}
my $m = Math::BigInt->new($LIB->_str($x->{_m}), undef, undef);
$m->bneg() if $x->{sign} eq '-';
$m;
}
sub exponent {
# return a copy of the exponent
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
if ($x->{sign} !~ /^[+-]$/) {
my $s = $x->{sign};
$s =~ s/^[+-]//;
return Math::BigInt->new($s, undef, undef); # -inf, +inf => +inf
}
Math::BigInt->new($x->{_es} . $LIB->_str($x->{_e}), undef, undef);
}
sub parts {
# return a copy of both the exponent and the mantissa
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
if ($x->{sign} !~ /^[+-]$/) {
my $s = $x->{sign};
$s =~ s/^\+//;
my $se = $s;
$se =~ s/^-//;
return ($class->new($s), $class->new($se)); # +inf => inf and -inf, +inf => inf
}
my $m = Math::BigInt->bzero();
$m->{value} = $LIB->_copy($x->{_m});
$m->bneg() if $x->{sign} eq '-';
($m, Math::BigInt->new($x->{_es} . $LIB->_num($x->{_e})));
}
sub sparts {
my $self = shift;
my $class = ref $self;
croak("sparts() is an instance method, not a class method")
unless $class;
# Not-a-number.
if ($self -> is_nan()) {
my $mant = $self -> copy(); # mantissa
return $mant unless wantarray; # scalar context
my $expo = $class -> bnan(); # exponent
return ($mant, $expo); # list context
}
# Infinity.
if ($self -> is_inf()) {
my $mant = $self -> copy(); # mantissa
return $mant unless wantarray; # scalar context
my $expo = $class -> binf('+'); # exponent
return ($mant, $expo); # list context
}
# Finite number.
my $mant = $self -> copy() -> bzero();
$mant -> {sign} = $self -> {sign};
$mant -> {_m} = $LIB->_copy($self -> {_m});
return $mant unless wantarray;
my $expo = $class -> bzero();
$expo -> {sign} = $self -> {_es};
$expo -> {_m} = $LIB->_copy($self -> {_e});
return ($mant, $expo);
}
sub nparts {
my $self = shift;
my $class = ref $self;
croak("nparts() is an instance method, not a class method")
unless $class;
# Not-a-number.
if ($self -> is_nan()) {
my $mant = $self -> copy(); # mantissa
return $mant unless wantarray; # scalar context
my $expo = $class -> bnan(); # exponent
return ($mant, $expo); # list context
}
# Infinity.
if ($self -> is_inf()) {
my $mant = $self -> copy(); # mantissa
return $mant unless wantarray; # scalar context
my $expo = $class -> binf('+'); # exponent
return ($mant, $expo); # list context
}
# Finite number.
my ($mant, $expo) = $self -> sparts();
if ($mant -> bcmp(0)) {
my ($ndigtot, $ndigfrac) = $mant -> length();
my $expo10adj = $ndigtot - $ndigfrac - 1;
if ($expo10adj != 0) {
my $factor = "1e" . -$expo10adj;
$mant -> bmul($factor);
return $mant unless wantarray;
$expo -> badd($expo10adj);
return ($mant, $expo);
}
}
return $mant unless wantarray;
return ($mant, $expo);
}
sub eparts {
my $self = shift;
my $class = ref $self;
croak("eparts() is an instance method, not a class method")
unless $class;
# Not-a-number and Infinity.
return $self -> sparts() if $self -> is_nan() || $self -> is_inf();
# Finite number.
my ($mant, $expo) = $self -> nparts();
my $c = $expo -> copy() -> bmod(3);
$mant -> blsft($c, 10);
return $mant unless wantarray;
$expo -> bsub($c);
return ($mant, $expo);
}
sub dparts {
my $self = shift;
my $class = ref $self;
croak("dparts() is an instance method, not a class method")
unless $class;
# Not-a-number and Infinity.
if ($self -> is_nan() || $self -> is_inf()) {
my $int = $self -> copy();
return $int unless wantarray;
my $frc = $class -> bzero();
return ($int, $frc);
}
my $int = $self -> copy();
my $frc = $class -> bzero();
# If the input has a fraction part.
if ($int->{_es} eq '-') {
$int->{_m} = $LIB -> _rsft($int->{_m}, $int->{_e}, 10);
$int->{_e} = $LIB -> _zero();
$int->{_es} = '+';
$int->{sign} = '+' if $LIB->_is_zero($int->{_m}); # avoid -0
return $int unless wantarray;
$frc = $self -> copy() -> bsub($int);
return ($int, $frc);
}
return $int unless wantarray;
return ($int, $frc);
}
sub fparts {
my $x = shift;
my $class = ref $x;
croak("fparts() is an instance method") unless $class;
return ($class -> bnan(),
$class -> bnan()) if $x -> is_nan();
return ($class -> binf($x -> sign()),
$class -> bone()) if $x -> is_inf();
return ($class -> bzero(),
$class -> bone()) if $x -> is_zero();
if ($x -> {_es} eq '-') { # exponent < 0
my $numer_lib = $LIB -> _copy($x -> {_m});
my $denom_lib = $LIB -> _1ex($x -> {_e});
my $gcd_lib = $LIB -> _gcd($LIB -> _copy($numer_lib), $denom_lib);
$numer_lib = $LIB -> _div($numer_lib, $gcd_lib);
$denom_lib = $LIB -> _div($denom_lib, $gcd_lib);
return ($class -> new($x -> {sign} . $LIB -> _str($numer_lib)),
$class -> new($LIB -> _str($denom_lib)));
}
elsif (! $LIB -> _is_zero($x -> {_e})) { # exponent > 0
my $numer_lib = $LIB -> _copy($x -> {_m});
$numer_lib = $LIB -> _lsft($numer_lib, $x -> {_e}, 10);
return ($class -> new($x -> {sign} . $LIB -> _str($numer_lib)),
$class -> bone());
}
else { # exponent = 0
return ($class -> new($x -> {sign} . $LIB -> _str($x -> {_m})),
$class -> bone());
}
}
sub numerator {
my $x = shift;
my $class = ref $x;
croak("numerator() is an instance method") unless $class;
return $class -> bnan() if $x -> is_nan();
return $class -> binf($x -> sign()) if $x -> is_inf();
return $class -> bzero() if $x -> is_zero();
if ($x -> {_es} eq '-') { # exponent < 0
my $numer_lib = $LIB -> _copy($x -> {_m});
my $denom_lib = $LIB -> _1ex($x -> {_e});
my $gcd_lib = $LIB -> _gcd($LIB -> _copy($numer_lib), $denom_lib);
$numer_lib = $LIB -> _div($numer_lib, $gcd_lib);
return $class -> new($x -> {sign} . $LIB -> _str($numer_lib));
}
elsif (! $LIB -> _is_zero($x -> {_e})) { # exponent > 0
my $numer_lib = $LIB -> _copy($x -> {_m});
$numer_lib = $LIB -> _lsft($numer_lib, $x -> {_e}, 10);
return $class -> new($x -> {sign} . $LIB -> _str($numer_lib));
}
else { # exponent = 0
return $class -> new($x -> {sign} . $LIB -> _str($x -> {_m}));
}
}
sub denominator {
my $x = shift;
my $class = ref $x;
croak("denominator() is an instance method") unless $class;
return $class -> bnan() if $x -> is_nan();
if ($x -> {_es} eq '-') { # exponent < 0
my $numer_lib = $LIB -> _copy($x -> {_m});
my $denom_lib = $LIB -> _1ex($x -> {_e});
my $gcd_lib = $LIB -> _gcd($LIB -> _copy($numer_lib), $denom_lib);
$denom_lib = $LIB -> _div($denom_lib, $gcd_lib);
return $class -> new($LIB -> _str($denom_lib));
}
else { # exponent >= 0
return $class -> bone();
}
}
###############################################################################
# String conversion methods
###############################################################################
sub bstr {
# (ref to BFLOAT or num_str) return num_str
# Convert number from internal format to (non-scientific) string format.
# internal format is always normalized (no leading zeros, "-0" => "+0")
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
if ($x->{sign} !~ /^[+-]$/) {
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
return 'inf'; # +inf
}
my $es = '0';
my $len = 1;
my $cad = 0;
my $dot = '.';
# $x is zero?
my $not_zero = !($x->{sign} eq '+' && $LIB->_is_zero($x->{_m}));
if ($not_zero) {
$es = $LIB->_str($x->{_m});
$len = CORE::length($es);
my $e = $LIB->_num($x->{_e});
$e = -$e if $x->{_es} eq '-';
if ($e < 0) {
$dot = '';
# if _e is bigger than a scalar, the following will blow your memory
if ($e <= -$len) {
my $r = abs($e) - $len;
$es = '0.'. ('0' x $r) . $es;
$cad = -($len+$r);
} else {
substr($es, $e, 0) = '.';
$cad = $LIB->_num($x->{_e});
$cad = -$cad if $x->{_es} eq '-';
}
} elsif ($e > 0) {
# expand with zeros
$es .= '0' x $e;
$len += $e;
$cad = 0;
}
} # if not zero
$es = '-'.$es if $x->{sign} eq '-';
# if set accuracy or precision, pad with zeros on the right side
if ((defined $x->{_a}) && ($not_zero)) {
# 123400 => 6, 0.1234 => 4, 0.001234 => 4
my $zeros = $x->{_a} - $cad; # cad == 0 => 12340
$zeros = $x->{_a} - $len if $cad != $len;
$es .= $dot.'0' x $zeros if $zeros > 0;
} elsif ((($x->{_p} || 0) < 0)) {
# 123400 => 6, 0.1234 => 4, 0.001234 => 6
my $zeros = -$x->{_p} + $cad;
$es .= $dot.'0' x $zeros if $zeros > 0;
}
$es;
}
# Decimal notation, e.g., "12345.6789".
sub bdstr {
my $x = shift;
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
return 'inf'; # +inf
}
my $mant = $LIB->_str($x->{_m});
my $expo = $x -> exponent();
my $str = $mant;
if ($expo >= 0) {
$str .= "0" x $expo;
} else {
my $mantlen = CORE::length($mant);
my $c = $mantlen + $expo;
$str = "0" x (1 - $c) . $str if $c <= 0;
substr($str, $expo, 0) = '.';
}
return $x->{sign} eq '-' ? "-$str" : $str;
}
# Scientific notation with significand/mantissa as an integer, e.g., "12345.6789"
# is written as "123456789e-4".
sub bsstr {
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
return 'inf'; # +inf
}
my $str = $LIB->_str($x->{_m}) . 'e' . $x->{_es}. $LIB->_str($x->{_e});
return $x->{sign} eq '-' ? "-$str" : $str;
}
# Normalized notation, e.g., "12345.6789" is written as "1.23456789e+4".
sub bnstr {
my $x = shift;
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
return 'inf'; # +inf
}
my ($mant, $expo) = $x -> nparts();
my $esgn = $expo < 0 ? '-' : '+';
my $eabs = $expo -> babs() -> bfround(0) -> bstr();
#$eabs = '0' . $eabs if length($eabs) < 2;
return $mant . 'e' . $esgn . $eabs;
}
# Engineering notation, e.g., "12345.6789" is written as "12.3456789e+3".
sub bestr {
my $x = shift;
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
return 'inf'; # +inf
}
my ($mant, $expo) = $x -> eparts();
my $esgn = $expo < 0 ? '-' : '+';
my $eabs = $expo -> babs() -> bfround(0) -> bstr();
#$eabs = '0' . $eabs if length($eabs) < 2;
return $mant . 'e' . $esgn . $eabs;
}
sub to_hex {
# return number as hexadecimal string (only for integers defined)
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
return '0' if $x->is_zero();
return $nan if $x->{_es} ne '+'; # how to do 1e-1 in hex?
my $z = $LIB->_copy($x->{_m});
if (! $LIB->_is_zero($x->{_e})) { # > 0
$z = $LIB->_lsft($z, $x->{_e}, 10);
}
my $str = $LIB->_to_hex($z);
return $x->{sign} eq '-' ? "-$str" : $str;
}
sub to_oct {
# return number as octal digit string (only for integers defined)
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
return '0' if $x->is_zero();
return $nan if $x->{_es} ne '+'; # how to do 1e-1 in octal?
my $z = $LIB->_copy($x->{_m});
if (! $LIB->_is_zero($x->{_e})) { # > 0
$z = $LIB->_lsft($z, $x->{_e}, 10);
}
my $str = $LIB->_to_oct($z);
return $x->{sign} eq '-' ? "-$str" : $str;
}
sub to_bin {
# return number as binary digit string (only for integers defined)
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
return '0' if $x->is_zero();
return $nan if $x->{_es} ne '+'; # how to do 1e-1 in binary?
my $z = $LIB->_copy($x->{_m});
if (! $LIB->_is_zero($x->{_e})) { # > 0
$z = $LIB->_lsft($z, $x->{_e}, 10);
}
my $str = $LIB->_to_bin($z);
return $x->{sign} eq '-' ? "-$str" : $str;
}
sub to_ieee754 {
my $x = shift;
my $format = shift;
my $class = ref $x;
my $enc; # significand encoding (applies only to decimal)
my $k; # storage width in bits
my $b; # base
if ($format =~ /^binary(\d+)\z/) {
$k = $1;
$b = 2;
} elsif ($format =~ /^decimal(\d+)(dpd|bcd)?\z/) {
$k = $1;
$b = 10;
$enc = $2 || 'dpd'; # default is dencely-packed decimals (DPD)
} elsif ($format eq 'half') {
$k = 16;
$b = 2;
} elsif ($format eq 'single') {
$k = 32;
$b = 2;
} elsif ($format eq 'double') {
$k = 64;
$b = 2;
} elsif ($format eq 'quadruple') {
$k = 128;
$b = 2;
} elsif ($format eq 'octuple') {
$k = 256;
$b = 2;
} elsif ($format eq 'sexdecuple') {
$k = 512;
$b = 2;
}
if ($b == 2) {
# Get the parameters for this format.
my $p; # precision (in bits)
my $t; # number of bits in significand
my $w; # number of bits in exponent
if ($k == 16) { # binary16 (half-precision)
$p = 11;
$t = 10;
$w = 5;
} elsif ($k == 32) { # binary32 (single-precision)
$p = 24;
$t = 23;
$w = 8;
} elsif ($k == 64) { # binary64 (double-precision)
$p = 53;
$t = 52;
$w = 11;
} else { # binaryN (quadruple-precition and above)
if ($k < 128 || $k != 32 * sprintf('%.0f', $k / 32)) {
croak "Number of bits must be 16, 32, 64, or >= 128 and",
" a multiple of 32";
}
$p = $k - sprintf('%.0f', 4 * log($k) / log(2)) + 13;
$t = $p - 1;
$w = $k - $t - 1;
}
# The maximum exponent, minimum exponent, and exponent bias.
my $emax = $class -> new(2) -> bpow($w - 1) -> bdec();
my $emin = 1 - $emax;
my $bias = $emax;
# Get numerical sign, exponent, and mantissa/significand for bit
# string.
my $sign = 0;
my $expo;
my $mant;
if ($x -> is_nan()) { # nan
$sign = 1;
$expo = $emax -> copy() -> binc();
$mant = $class -> new(2) -> bpow($t - 1);
} elsif ($x -> is_inf()) { # inf
$sign = 1 if $x -> is_neg();
$expo = $emax -> copy() -> binc();
$mant = $class -> bzero();
} elsif ($x -> is_zero()) { # zero
$expo = $emin -> copy() -> bdec();
$mant = $class -> bzero();
} else { # normal and subnormal
$sign = 1 if $x -> is_neg();
# Now we need to compute the mantissa and exponent in base $b.
my $binv = $class -> new("0.5");
my $b = $class -> new(2);
my $one = $class -> bone();
# We start off by initializing the exponent to zero and the
# mantissa to the input value. Then we increase the mantissa and
# decrease the exponent, or vice versa, until the mantissa is in
# the desired range or we hit one of the limits for the exponent.
$mant = $x -> copy() -> babs();
# We need to find the base 2 exponent. First make an estimate of
# the base 2 exponent, before adjusting it below. We could skip
# this estimation and go straight to the while-loops below, but the
# loops are slow, especially when the final exponent is far from
# zero and even more so if the number of digits is large. This
# initial estimation speeds up the computation dramatically.
#
# log2($m * 10**$e) = log10($m + 10**$e) * log(10)/log(2)
# = (log10($m) + $e) * log(10)/log(2)
# = (log($m)/log(10) + $e) * log(10)/log(2)
my ($m, $e) = $x -> nparts();
my $ms = $m -> numify();
my $es = $e -> numify();
my $expo_est = (log(abs($ms))/log(10) + $es) * log(10)/log(2);
$expo_est = int($expo_est);
# Limit the exponent.
if ($expo_est > $emax) {
$expo_est = $emax;
} elsif ($expo_est < $emin) {
$expo_est = $emin;
}
# Don't multiply by a number raised to a negative exponent. This
# will cause a division, whose result is truncated to some fixed
# number of digits. Instead, multiply by the inverse number raised
# to a positive exponent.
$expo = $class -> new($expo_est);
if ($expo_est > 0) {
$mant -> bmul($binv -> copy() -> bpow($expo));
} elsif ($expo_est < 0) {
my $expo_abs = $expo -> copy() -> bneg();
$mant -> bmul($b -> copy() -> bpow($expo_abs));
}
# Final adjustment of the estimate above.
while ($mant >= $b && $expo <= $emax) {
$mant -> bmul($binv);
$expo -> binc();
}
while ($mant < $one && $expo >= $emin) {
$mant -> bmul($b);
$expo -> bdec();
}
# This is when the magnitude is larger than what can be represented
# in this format. Encode as infinity.
if ($expo > $emax) {
$mant = $class -> bzero();
$expo = $emax -> copy() -> binc();
}
# This is when the magnitude is so small that the number is encoded
# as a subnormal number.
#
# If the magnitude is smaller than that of the smallest subnormal
# number, and rounded downwards, it is encoded as zero. This works
# transparently and does not need to be treated as a special case.
#
# If the number is between the largest subnormal number and the
# smallest normal number, and the value is rounded upwards, the
# value must be encoded as a normal number. This must be treated as
# a special case.
elsif ($expo < $emin) {
# Scale up the mantissa (significand), and round to integer.
my $const = $class -> new($b) -> bpow($t - 1);
$mant -> bmul($const);
$mant -> bfround(0);
# If the mantissa overflowed, encode as the smallest normal
# number.
if ($mant == $const -> bmul($b)) {
$mant -> bzero();
$expo -> binc();
}
}
# This is when the magnitude is within the range of what can be
# encoded as a normal number.
else {
# Remove implicit leading bit, scale up the mantissa
# (significand) to an integer, and round.
$mant -> bdec();
my $const = $class -> new($b) -> bpow($t);
$mant -> bmul($const) -> bfround(0);
# If the mantissa overflowed, encode as the next larger value.
# This works correctly also when the next larger value is
# infinity.
if ($mant == $const) {
$mant -> bzero();
$expo -> binc();
}
}
}
$expo -> badd($bias); # add bias
my $signbit = "$sign";
my $mantbits = $mant -> to_bin();
$mantbits = ("0" x ($t - CORE::length($mantbits))) . $mantbits;
my $expobits = $expo -> to_bin();
$expobits = ("0" x ($w - CORE::length($expobits))) . $expobits;
my $bin = $signbit . $expobits . $mantbits;
return pack "B*", $bin;
}
croak("The format '$format' is not yet supported.");
}
sub as_hex {
# return number as hexadecimal string (only for integers defined)
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
return '0x0' if $x->is_zero();
return $nan if $x->{_es} ne '+'; # how to do 1e-1 in hex?
my $z = $LIB->_copy($x->{_m});
if (! $LIB->_is_zero($x->{_e})) { # > 0
$z = $LIB->_lsft($z, $x->{_e}, 10);
}
my $str = $LIB->_as_hex($z);
return $x->{sign} eq '-' ? "-$str" : $str;
}
sub as_oct {
# return number as octal digit string (only for integers defined)
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
return '00' if $x->is_zero();
return $nan if $x->{_es} ne '+'; # how to do 1e-1 in octal?
my $z = $LIB->_copy($x->{_m});
if (! $LIB->_is_zero($x->{_e})) { # > 0
$z = $LIB->_lsft($z, $x->{_e}, 10);
}
my $str = $LIB->_as_oct($z);
return $x->{sign} eq '-' ? "-$str" : $str;
}
sub as_bin {
# return number as binary digit string (only for integers defined)
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
return '0b0' if $x->is_zero();
return $nan if $x->{_es} ne '+'; # how to do 1e-1 in binary?
my $z = $LIB->_copy($x->{_m});
if (! $LIB->_is_zero($x->{_e})) { # > 0
$z = $LIB->_lsft($z, $x->{_e}, 10);
}
my $str = $LIB->_as_bin($z);
return $x->{sign} eq '-' ? "-$str" : $str;
}
sub numify {
# Make a Perl scalar number from a Math::BigFloat object.
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
if ($x -> is_nan()) {
require Math::Complex;
my $inf = $Math::Complex::Inf;
return $inf - $inf;
}
if ($x -> is_inf()) {
require Math::Complex;
my $inf = $Math::Complex::Inf;
return $x -> is_negative() ? -$inf : $inf;
}
# Create a string and let Perl's atoi()/atof() handle the rest.
return 0 + $x -> bnstr();
}
###############################################################################
# Private methods and functions.
###############################################################################
sub import {
my $class = shift;
$IMPORT++; # remember we did import()
my @import = ('objectify');
my @a; # unrecognized arguments
while (@_) {
my $param = shift;
# Enable overloading of constants.
if ($param eq ':constant') {
overload::constant
integer => sub {
$class -> new(shift);
},
float => sub {
$class -> new(shift);
},
binary => sub {
# E.g., a literal 0377 shall result in an object whose value
# is decimal 255, but new("0377") returns decimal 377.
return $class -> from_oct($_[0]) if $_[0] =~ /^0_*[0-7]/;
$class -> new(shift);
};
next;
}
# Upgrading.
if ($param eq 'upgrade') {
$class -> upgrade(shift);
next;
}
# Downgrading.
if ($param eq 'downgrade') {
$class -> downgrade(shift);
next;
}
# Accuracy.
if ($param eq 'accuracy') {
$class -> accuracy(shift);
next;
}
# Precision.
if ($param eq 'precision') {
$class -> precision(shift);
next;
}
# Rounding mode.
if ($param eq 'round_mode') {
$class -> round_mode(shift);
next;
}
# Backend library.
if ($param =~ /^(lib|try|only)\z/) {
push @import, $param;
push @import, shift() if @_;
next;
}
if ($param eq 'with') {
# alternative class for our private parts()
# XXX: no longer supported
# $LIB = shift() || 'Calc';
# carp "'with' is no longer supported, use 'lib', 'try', or 'only'";
shift;
next;
}
# Unrecognized parameter.
push @a, $param;
}
Math::BigInt -> import(@import);
# find out which one was actually loaded
$LIB = Math::BigInt -> config('lib');
$class->export_to_level(1, $class, @a); # export wanted functions
}
sub _len_to_steps {
# Given D (digits in decimal), compute N so that N! (N factorial) is
# at least D digits long. D should be at least 50.
my $d = shift;
# two constants for the Ramanujan estimate of ln(N!)
my $lg2 = log(2 * 3.14159265) / 2;
my $lg10 = log(10);
# D = 50 => N => 42, so L = 40 and R = 50
my $l = 40;
my $r = $d;
# Otherwise this does not work under -Mbignum and we do not yet have "no bignum;" :(
$l = $l->numify if ref($l);
$r = $r->numify if ref($r);
$lg2 = $lg2->numify if ref($lg2);
$lg10 = $lg10->numify if ref($lg10);
# binary search for the right value (could this be written as the reverse of lg(n!)?)
while ($r - $l > 1) {
my $n = int(($r - $l) / 2) + $l;
my $ramanujan =
int(($n * log($n) - $n + log($n * (1 + 4*$n*(1+2*$n))) / 6 + $lg2) / $lg10);
$ramanujan > $d ? $r = $n : $l = $n;
}
$l;
}
sub _log {
# internal log function to calculate ln() based on Taylor series.
# Modifies $x in place.
my ($x, $scale) = @_;
my $class = ref $x;
# in case of $x == 1, result is 0
return $x->bzero() if $x->is_one();
# XXX TODO: rewrite this in a similar manner to bexp()
# http://www.efunda.com/math/taylor_series/logarithmic.cfm?search_string=log
# u = x-1, v = x+1
# _ _
# 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 and is thus not used
# u = x-1
# _ _
# Taylor: | u 1 u^2 1 u^3 |
# ln (x) = 2 | --- + - * --- + - * --- + ... | x > 1/2
# |_ x 2 x^2 3 x^3 _|
my ($limit, $v, $u, $below, $factor, $next, $over, $f);
$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 = $class->new(3); $f = $class->new(2);
$limit = $class->new("1E-". ($scale-1));
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
# calculating the next term simple from over/below will result in quite
# a time hog if the input has many digits, since over and below will
# accumulate more and more digits, and the result will also have many
# digits, but in the end it is rounded to $scale digits anyway. So if we
# round $over and $below first, we save a lot of time for the division
# (not with log(1.2345), but try log (123**123) to see what I mean. This
# can introduce a rounding error if the division result would be f.i.
# 0.1234500000001 and we round it to 5 digits it would become 0.12346, but
# if we truncated $over and $below we might get 0.12345. Does this matter
# for the end result? So we give $over and $below 4 more digits to be
# on the safe side (unscientific error handling as usual... :+D
$next = $over->copy()->bround($scale+4)
->bdiv($below->copy()->bmul($factor)->bround($scale+4),
$scale);
## old version:
## $next = $over->copy()->bdiv($below->copy()->bmul($factor), $scale);
last if $next->bacmp($limit) <= 0;
delete $next->{_a};
delete $next->{_p};
$x->badd($next);
# calculate things for the next term
$over *= $u;
$below *= $v;
$factor->badd($f);
}
$x->bmul($f); # $x *= 2
}
sub _log_10 {
# Internal log function based on reducing input to the range of 0.1 .. 9.99
# and then "correcting" the result to the proper one. Modifies $x in place.
my ($x, $scale) = @_;
my $class = ref $x;
# Taking blog() from numbers greater than 10 takes a *very long* time, so we
# break the computation down into parts based on the observation that:
# blog(X*Y) = blog(X) + blog(Y)
# We set Y here to multiples of 10 so that $x becomes below 1 - the smaller
# $x is the faster it gets. Since 2*$x takes about 10 times as
# long, we make it faster by about a factor of 100 by dividing $x by 10.
# The same observation is valid for numbers smaller than 0.1, e.g. computing
# log(1) is fastest, and the further away we get from 1, the longer it takes.
# So we also 'break' this down by multiplying $x with 10 and subtract the
# log(10) afterwards to get the correct result.
# To get $x even closer to 1, we also divide by 2 and then use log(2) to
# correct for this. For instance if $x is 2.4, we use the formula:
# blog(2.4 * 2) == blog(1.2) + blog(2)
# and thus calculate only blog(1.2) and blog(2), which is faster in total
# than calculating blog(2.4).
# In addition, the values for blog(2) and blog(10) are cached.
# Calculate nr of digits before dot. x = 123, dbd = 3; x = 1.23, dbd = 1;
# x = 0.0123, dbd = -1; x = 0.000123, dbd = -3, etc.
my $dbd = $LIB->_num($x->{_e});
$dbd = -$dbd if $x->{_es} eq '-';
$dbd += $LIB->_len($x->{_m});
# more than one digit (e.g. at least 10), but *not* exactly 10 to avoid
# infinite recursion
my $calc = 1; # do some calculation?
# disable the shortcut for 10, since we need log(10) and this would recurse
# infinitely deep
if ($x->{_es} eq '+' && # $x == 10
($LIB->_is_one($x->{_e}) &&
$LIB->_is_one($x->{_m})))
{
$dbd = 0; # disable shortcut
# we can use the cached value in these cases
if ($scale <= $LOG_10_A) {
$x->bzero();
$x->badd($LOG_10); # modify $x in place
$calc = 0; # no need to calc, but round
}
# if we can't use the shortcut, we continue normally
} else {
# disable the shortcut for 2, since we maybe have it cached
if (($LIB->_is_zero($x->{_e}) && # $x == 2
$LIB->_is_two($x->{_m})))
{
$dbd = 0; # disable shortcut
# we can use the cached value in these cases
if ($scale <= $LOG_2_A) {
$x->bzero();
$x->badd($LOG_2); # modify $x in place
$calc = 0; # no need to calc, but round
}
# if we can't use the shortcut, we continue normally
}
}
# if $x = 0.1, we know the result must be 0-log(10)
if ($calc != 0 &&
($x->{_es} eq '-' && # $x == 0.1
($LIB->_is_one($x->{_e}) &&
$LIB->_is_one($x->{_m}))))
{
$dbd = 0; # disable shortcut
# we can use the cached value in these cases
if ($scale <= $LOG_10_A) {
$x->bzero();
$x->bsub($LOG_10);
$calc = 0; # no need to calc, but round
}
}
return $x if $calc == 0; # already have the result
# default: these correction factors are undef and thus not used
my $l_10; # value of ln(10) to A of $scale
my $l_2; # value of ln(2) to A of $scale
my $two = $class->new(2);
# $x == 2 => 1, $x == 13 => 2, $x == 0.1 => 0, $x == 0.01 => -1
# so don't do this shortcut for 1 or 0
if (($dbd > 1) || ($dbd < 0)) {
# convert our cached value to an object if not already (avoid doing this
# at import() time, since not everybody needs this)
$LOG_10 = $class->new($LOG_10, undef, undef) unless ref $LOG_10;
#print "x = $x, dbd = $dbd, calc = $calc\n";
# got more than one digit before the dot, or more than one zero after the
# dot, so do:
# log(123) == log(1.23) + log(10) * 2
# log(0.0123) == log(1.23) - log(10) * 2
if ($scale <= $LOG_10_A) {
# use cached value
$l_10 = $LOG_10->copy(); # copy for mul
} else {
# else: slower, compute and cache result
# also disable downgrade for this code path
local $Math::BigFloat::downgrade = undef;
# shorten the time to calculate log(10) based on the following:
# log(1.25 * 8) = log(1.25) + log(8)
# = log(1.25) + log(2) + log(2) + log(2)
# first get $l_2 (and possible compute and cache log(2))
$LOG_2 = $class->new($LOG_2, undef, undef) unless ref $LOG_2;
if ($scale <= $LOG_2_A) {
# use cached value
$l_2 = $LOG_2->copy(); # copy() for the mul below
} else {
# else: slower, compute and cache result
$l_2 = $two->copy();
$l_2->_log($scale); # scale+4, actually
$LOG_2 = $l_2->copy(); # cache the result for later
# the copy() is for mul below
$LOG_2_A = $scale;
}
# now calculate log(1.25):
$l_10 = $class->new('1.25');
$l_10->_log($scale); # scale+4, actually
# log(1.25) + log(2) + log(2) + log(2):
$l_10->badd($l_2);
$l_10->badd($l_2);
$l_10->badd($l_2);
$LOG_10 = $l_10->copy(); # cache the result for later
# the copy() is for mul below
$LOG_10_A = $scale;
}
$dbd-- if ($dbd > 1); # 20 => dbd=2, so make it dbd=1
$l_10->bmul($class->new($dbd)); # log(10) * (digits_before_dot-1)
my $dbd_sign = '+';
if ($dbd < 0) {
$dbd = -$dbd;
$dbd_sign = '-';
}
($x->{_e}, $x->{_es}) =
_e_sub($x->{_e}, $LIB->_new($dbd), $x->{_es}, $dbd_sign); # 123 => 1.23
#($x->{_e}, $x->{_es}) =
# $LIB -> _ssub($x->{_e}, $x->{_es}, $LIB->_new($dbd), $dbd_sign);
}
# Now: 0.1 <= $x < 10 (and possible correction in l_10)
### Since $x in the range 0.5 .. 1.5 is MUCH faster, we do a repeated div
### or mul by 2 (maximum times 3, since x < 10 and x > 0.1)
$HALF = $class->new($HALF) unless ref($HALF);
my $twos = 0; # default: none (0 times)
while ($x->bacmp($HALF) <= 0) { # X <= 0.5
$twos--;
$x->bmul($two);
}
while ($x->bacmp($two) >= 0) { # X >= 2
$twos++;
$x->bdiv($two, $scale+4); # keep all digits
}
$x->bround($scale+4);
# $twos > 0 => did mul 2, < 0 => did div 2 (but we never did both)
# So calculate correction factor based on ln(2):
if ($twos != 0) {
$LOG_2 = $class->new($LOG_2, undef, undef) unless ref $LOG_2;
if ($scale <= $LOG_2_A) {
# use cached value
$l_2 = $LOG_2->copy(); # copy() for the mul below
} else {
# else: slower, compute and cache result
# also disable downgrade for this code path
local $Math::BigFloat::downgrade = undef;
$l_2 = $two->copy();
$l_2->_log($scale); # scale+4, actually
$LOG_2 = $l_2->copy(); # cache the result for later
# the copy() is for mul below
$LOG_2_A = $scale;
}
$l_2->bmul($twos); # * -2 => subtract, * 2 => add
} else {
undef $l_2;
}
$x->_log($scale); # need to do the "normal" way
$x->badd($l_10) if defined $l_10; # correct it by ln(10)
$x->badd($l_2) if defined $l_2; # and maybe by ln(2)
# all done, $x contains now the result
$x;
}
sub _e_add {
# Internal helper sub to take two positive integers and their signs and
# then add them. Input ($LIB, $LIB, ('+'|'-'), ('+'|'-')), output
# ($LIB, ('+'|'-')).
my ($x, $y, $xs, $ys) = @_;
# if the signs are equal we can add them (-5 + -3 => -(5 + 3) => -8)
if ($xs eq $ys) {
$x = $LIB->_add($x, $y); # +a + +b or -a + -b
} else {
my $a = $LIB->_acmp($x, $y);
if ($a == 0) {
# This does NOT modify $x in-place. TODO: Fix this?
$x = $LIB->_zero(); # result is 0
$xs = '+';
return ($x, $xs);
}
if ($a > 0) {
$x = $LIB->_sub($x, $y); # abs sub
} else { # a < 0
$x = $LIB->_sub ($y, $x, 1); # abs sub
$xs = $ys;
}
}
$xs = '+' if $xs eq '-' && $LIB->_is_zero($x); # no "-0"
return ($x, $xs);
}
sub _e_sub {
# Internal helper sub to take two positive integers and their signs and
# then subtract them. Input ($LIB, $LIB, ('+'|'-'), ('+'|'-')),
# output ($LIB, ('+'|'-'))
my ($x, $y, $xs, $ys) = @_;
# flip sign
$ys = $ys eq '+' ? '-' : '+'; # swap sign of second operand ...
_e_add($x, $y, $xs, $ys); # ... and let _e_add() do the job
#$LIB -> _sadd($x, $xs, $y, $ys); # ... and let $LIB -> _sadd() do the job
}
sub _pow {
# Calculate a power where $y is a non-integer, like 2 ** 0.3
my ($x, $y, @r) = @_;
my $class = ref($x);
# if $y == 0.5, it is sqrt($x)
$HALF = $class->new($HALF) unless ref($HALF);
return $x->bsqrt(@r, $y) if $y->bcmp($HALF) == 0;
# Using:
# a ** x == e ** (x * ln a)
# 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, @params);
($x, @params) = $x->_find_round_parameters(@r);
return $x if $x->is_nan(); # error in _find_round_parameters?
# no rounding at all, so must use fallback
if (scalar @params == 0) {
# simulate old behaviour
$params[0] = $class->div_scale(); # and round to it as accuracy
$params[1] = undef; # disable P
$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 {
# the 4 below is empirical, and there might be cases where it is not
# enough...
$scale = abs($params[0] || $params[1]) + 4; # take whatever is defined
}
# when user set globals, they would interfere with our calculation, so
# disable them and later re-enable them
no strict 'refs';
my $abr = "$class\::accuracy"; my $ab = $$abr; $$abr = undef;
my $pbr = "$class\::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(undef, $scale)->bmul($y);
my $do_invert = ($u->{sign} eq '-');
$u->bneg() if $do_invert;
$v = $class->bone(); # 1
$factor = $class->new(2); # 2
$x->bone(); # first term: 1
$below = $v->copy();
$over = $u->copy();
$limit = $class->new("1E-". ($scale-1));
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->bacmp($limit) <= 0;
$x->badd($next);
# calculate things for the next term
$over *= $u;
$below *= $factor;
$factor->binc();
last if $x->{sign} !~ /^[-+]$/;
}
if ($do_invert) {
my $x_copy = $x->copy();
$x->bone->bdiv($x_copy, $scale);
}
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x->bround($params[0], $params[2]); # then round accordingly
} else {
$x->bfround($params[1], $params[2]); # then round accordingly
}
if ($fallback) {
# clear a/p after round, since user did not request it
delete $x->{_a};
delete $x->{_p};
}
# restore globals
$$abr = $ab;
$$pbr = $pb;
$x;
}
1;
__END__
=pod
=head1 NAME
Math::BigFloat - Arbitrary size floating point math package
=head1 SYNOPSIS
use Math::BigFloat;
# Configuration methods (may be used as class methods and instance methods)
Math::BigFloat->accuracy(); # get class accuracy
Math::BigFloat->accuracy($n); # set class accuracy
Math::BigFloat->precision(); # get class precision
Math::BigFloat->precision($n); # set class precision
Math::BigFloat->round_mode(); # get class rounding mode
Math::BigFloat->round_mode($m); # set global round mode, must be one of
# 'even', 'odd', '+inf', '-inf', 'zero',
# 'trunc', or 'common'
Math::BigFloat->config("lib"); # name of backend math library
# Constructor methods (when the class methods below are used as instance
# methods, the value is assigned the invocand)
$x = Math::BigFloat->new($str); # defaults to 0
$x = Math::BigFloat->new('0x123'); # from hexadecimal
$x = Math::BigFloat->new('0o377'); # from octal
$x = Math::BigFloat->new('0b101'); # from binary
$x = Math::BigFloat->from_hex('0xc.afep+3'); # from hex
$x = Math::BigFloat->from_hex('cafe'); # ditto
$x = Math::BigFloat->from_oct('1.3267p-4'); # from octal
$x = Math::BigFloat->from_oct('01.3267p-4'); # ditto
$x = Math::BigFloat->from_oct('0o1.3267p-4'); # ditto
$x = Math::BigFloat->from_oct('0377'); # ditto
$x = Math::BigFloat->from_bin('0b1.1001p-4'); # from binary
$x = Math::BigFloat->from_bin('0101'); # ditto
$x = Math::BigFloat->from_ieee754($b, "binary64"); # from IEEE-754 bytes
$x = Math::BigFloat->bzero(); # create a +0
$x = Math::BigFloat->bone(); # create a +1
$x = Math::BigFloat->bone('-'); # create a -1
$x = Math::BigFloat->binf(); # create a +inf
$x = Math::BigFloat->binf('-'); # create a -inf
$x = Math::BigFloat->bnan(); # create a Not-A-Number
$x = Math::BigFloat->bpi(); # returns pi
$y = $x->copy(); # make a copy (unlike $y = $x)
$y = $x->as_int(); # return as BigInt
# Boolean methods (these don't modify the invocand)
$x->is_zero(); # if $x is 0
$x->is_one(); # if $x is +1
$x->is_one("+"); # ditto
$x->is_one("-"); # if $x is -1
$x->is_inf(); # if $x is +inf or -inf
$x->is_inf("+"); # if $x is +inf
$x->is_inf("-"); # if $x is -inf
$x->is_nan(); # if $x is NaN
$x->is_positive(); # if $x > 0
$x->is_pos(); # ditto
$x->is_negative(); # if $x < 0
$x->is_neg(); # ditto
$x->is_odd(); # if $x is odd
$x->is_even(); # if $x is even
$x->is_int(); # if $x is an integer
# Comparison methods
$x->bcmp($y); # compare numbers (undef, < 0, == 0, > 0)
$x->bacmp($y); # compare absolutely (undef, < 0, == 0, > 0)
$x->beq($y); # true if and only if $x == $y
$x->bne($y); # true if and only if $x != $y
$x->blt($y); # true if and only if $x < $y
$x->ble($y); # true if and only if $x <= $y
$x->bgt($y); # true if and only if $x > $y
$x->bge($y); # true if and only if $x >= $y
# Arithmetic methods
$x->bneg(); # negation
$x->babs(); # absolute value
$x->bsgn(); # sign function (-1, 0, 1, or NaN)
$x->bnorm(); # normalize (no-op)
$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->bmuladd($y,$z); # $x = $x * $y + $z
$x->bdiv($y); # division (floored), set $x to quotient
# return (quo,rem) or quo if scalar
$x->btdiv($y); # division (truncated), set $x to quotient
# return (quo,rem) or quo if scalar
$x->bmod($y); # modulus (x % y)
$x->btmod($y); # modulus (truncated)
$x->bmodinv($mod); # modular multiplicative inverse
$x->bmodpow($y,$mod); # modular exponentiation (($x ** $y) % $mod)
$x->bpow($y); # power of arguments (x ** y)
$x->blog(); # logarithm of $x to base e (Euler's number)
$x->blog($base); # logarithm of $x to base $base (e.g., base 2)
$x->bexp(); # calculate e ** $x where e is Euler's number
$x->bnok($y); # x over y (binomial coefficient n over k)
$x->bsin(); # sine
$x->bcos(); # cosine
$x->batan(); # inverse tangent
$x->batan2($y); # two-argument inverse tangent
$x->bsqrt(); # calculate square root
$x->broot($y); # $y'th root of $x (e.g. $y == 3 => cubic root)
$x->bfac(); # factorial of $x (1*2*3*4*..$x)
$x->blsft($n); # left shift $n places in base 2
$x->blsft($n,$b); # left shift $n places in base $b
# returns (quo,rem) or quo (scalar context)
$x->brsft($n); # right shift $n places in base 2
$x->brsft($n,$b); # right shift $n places in base $b
# returns (quo,rem) or quo (scalar context)
# Bitwise methods
$x->band($y); # bitwise and
$x->bior($y); # bitwise inclusive or
$x->bxor($y); # bitwise exclusive or
$x->bnot(); # bitwise not (two's complement)
# Rounding methods
$x->round($A,$P,$mode); # round to accuracy or precision using
# rounding mode $mode
$x->bround($n); # accuracy: preserve $n digits
$x->bfround($n); # $n > 0: round to $nth digit left of dec. point
# $n < 0: round to $nth digit right of dec. point
$x->bfloor(); # round towards minus infinity
$x->bceil(); # round towards plus infinity
$x->bint(); # round towards zero
# Other mathematical methods
$x->bgcd($y); # greatest common divisor
$x->blcm($y); # least common multiple
# Object property methods (do not modify the invocand)
$x->sign(); # the sign, either +, - or NaN
$x->digit($n); # the nth digit, counting from the right
$x->digit(-$n); # the nth digit, counting from the left
$x->length(); # return number of digits in number
($xl,$f) = $x->length(); # length of number and length of fraction
# part, latter is always 0 digits long
# for Math::BigInt objects
$x->mantissa(); # return (signed) mantissa as BigInt
$x->exponent(); # return exponent as BigInt
$x->parts(); # return (mantissa,exponent) as BigInt
$x->sparts(); # mantissa and exponent (as integers)
$x->nparts(); # mantissa and exponent (normalised)
$x->eparts(); # mantissa and exponent (engineering notation)
$x->dparts(); # integer and fraction part
$x->fparts(); # numerator and denominator
$x->numerator(); # numerator
$x->denominator(); # denominator
# Conversion methods (do not modify the invocand)
$x->bstr(); # decimal notation, possibly zero padded
$x->bsstr(); # string in scientific notation with integers
$x->bnstr(); # string in normalized notation
$x->bestr(); # string in engineering notation
$x->bdstr(); # string in decimal notation
$x->as_hex(); # as signed hexadecimal string with prefixed 0x
$x->as_bin(); # as signed binary string with prefixed 0b
$x->as_oct(); # as signed octal string with prefixed 0
$x->to_ieee754($format); # to bytes encoded according to IEEE 754-2008
# Other conversion methods
$x->numify(); # return as scalar (might overflow or underflow)
=head1 DESCRIPTION
Math::BigFloat provides support for arbitrary precision floating point.
Overloading is also provided for Perl operators.
All operators (including basic math operations) are overloaded if you
declare your big floating point numbers as
$x = Math::BigFloat -> new('12_3.456_789_123_456_789E-2');
Operations with overloaded operators preserve the arguments, which is
exactly what you expect.
=head2 Input
Input values to these routines may be any scalar number or string that looks
like a number. Anything that is accepted by Perl as a literal numeric constant
should be accepted by this module.
=over
=item *
Leading and trailing whitespace is ignored.
=item *
Leading zeros are ignored, except for floating point numbers with a binary
exponent, in which case the number is interpreted as an octal floating point
number. For example, "01.4p+0" gives 1.5, "00.4p+0" gives 0.5, but "0.4p+0"
gives a NaN. And while "0377" gives 255, "0377p0" gives 255.
=item *
If the string has a "0x" or "0X" prefix, it is interpreted as a hexadecimal
number.
=item *
If the string has a "0o" or "0O" prefix, it is interpreted as an octal number. A
floating point literal with a "0" prefix is also interpreted as an octal number.
=item *
If the string has a "0b" or "0B" prefix, it is interpreted as a binary number.
=item *
Underline characters are allowed in the same way as they are allowed in literal
numerical constants.
=item *
If the string can not be interpreted, NaN is returned.
=item *
For hexadecimal, octal, and binary floating point numbers, the exponent must be
separated from the significand (mantissa) by the letter "p" or "P", not "e" or
"E" as with decimal numbers.
=back
Some examples of valid string input
Input string Resulting value
123 123
1.23e2 123
12300e-2 123
67_538_754 67538754
-4_5_6.7_8_9e+0_1_0 -4567890000000
0x13a 314
0x13ap0 314
0x1.3ap+8 314
0x0.00013ap+24 314
0x13a000p-12 314
0o472 314
0o1.164p+8 314
0o0.0001164p+20 314
0o1164000p-10 314
0472 472 Note!
01.164p+8 314
00.0001164p+20 314
01164000p-10 314
0b100111010 314
0b1.0011101p+8 314
0b0.00010011101p+12 314
0b100111010000p-3 314
0x1.921fb5p+1 3.14159262180328369140625e+0
0o1.2677025p1 2.71828174591064453125
01.2677025p1 2.71828174591064453125
0b1.1001p-4 9.765625e-2
=head2 Output
Output values are usually Math::BigFloat objects.
Boolean operators C, C, C, etc. return true or
false.
Comparison operators C and C) return -1, 0, 1, or
undef.
=head1 METHODS
Math::BigFloat supports all methods that Math::BigInt supports, except it
calculates non-integer results when possible. Please see L for a
full description of each method. Below are just the most important differences:
=head2 Configuration methods
=over
=item 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, 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 explicitly using one of
L, L or L
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
=item 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 instead. With L you
set the number of digits each result should have, with L you
set the place where to round!
=back
=head2 Constructor methods
=over
=item from_hex()
$x -> from_hex("0x1.921fb54442d18p+1");
$x = Math::BigFloat -> from_hex("0x1.921fb54442d18p+1");
Interpret input as a hexadecimal string.A prefix ("0x", "x", ignoring case) is
optional. A single underscore character ("_") may be placed between any two
digits. If the input is invalid, a NaN is returned. The exponent is in base 2
using decimal digits.
If called as an instance method, the value is assigned to the invocand.
=item from_oct()
$x -> from_oct("1.3267p-4");
$x = Math::BigFloat -> from_oct("1.3267p-4");
Interpret input as an octal string. A single underscore character ("_") may be
placed between any two digits. If the input is invalid, a NaN is returned. The
exponent is in base 2 using decimal digits.
If called as an instance method, the value is assigned to the invocand.
=item from_bin()
$x -> from_bin("0b1.1001p-4");
$x = Math::BigFloat -> from_bin("0b1.1001p-4");
Interpret input as a hexadecimal string. A prefix ("0b" or "b", ignoring case)
is optional. A single underscore character ("_") may be placed between any two
digits. If the input is invalid, a NaN is returned. The exponent is in base 2
using decimal digits.
If called as an instance method, the value is assigned to the invocand.
=item from_ieee754()
Interpret the input as a value encoded as described in IEEE754-2008. The input
can be given as a byte string, hex string or binary string. The input is
assumed to be in big-endian byte-order.
# both $dbl and $mbf are 3.141592...
$bytes = "\x40\x09\x21\xfb\x54\x44\x2d\x18";
$dbl = unpack "d>", $bytes;
$mbf = Math::BigFloat -> from_ieee754($bytes, "binary64");
=item bpi()
print Math::BigFloat->bpi(100), "\n";
Calculate PI to N digits (including the 3 before the dot). The result is
rounded according to the current rounding mode, which defaults to "even".
This method was added in v1.87 of Math::BigInt (June 2007).
=back
=head2 Arithmetic methods
=over
=item bmuladd()
$x->bmuladd($y,$z);
Multiply $x by $y, and then add $z to the result.
This method was added in v1.87 of Math::BigInt (June 2007).
=item bdiv()
$q = $x->bdiv($y);
($q, $r) = $x->bdiv($y);
In scalar context, divides $x by $y and returns the result to the given or
default accuracy/precision. In list context, does floored division
(F-division), returning an integer $q and a remainder $r so that $x = $q * $y +
$r. The remainer (modulo) is equal to what is returned by C<< $x->bmod($y) >>.
=item bmod()
$x->bmod($y);
Returns $x modulo $y. When $x is finite, and $y is finite and non-zero, the
result is identical to the remainder after floored division (F-division). If,
in addition, both $x and $y are integers, the result is identical to the result
from Perl's % operator.
=item bexp()
$x->bexp($accuracy); # calculate e ** X
Calculates the expression C where C is Euler's number.
This method was added in v1.82 of Math::BigInt (April 2007).
=item bnok()
$x->bnok($y); # x over y (binomial coefficient n over k)
Calculates the binomial coefficient n over k, also called the "choose"
function. The result is equivalent to:
( n ) n!
| - | = -------
( k ) k!(n-k)!
This method was added in v1.84 of Math::BigInt (April 2007).
=item bsin()
my $x = Math::BigFloat->new(1);
print $x->bsin(100), "\n";
Calculate the sinus of $x, modifying $x in place.
This method was added in v1.87 of Math::BigInt (June 2007).
=item bcos()
my $x = Math::BigFloat->new(1);
print $x->bcos(100), "\n";
Calculate the cosinus of $x, modifying $x in place.
This method was added in v1.87 of Math::BigInt (June 2007).
=item batan()
my $x = Math::BigFloat->new(1);
print $x->batan(100), "\n";
Calculate the arcus tanges of $x, modifying $x in place. See also L.
This method was added in v1.87 of Math::BigInt (June 2007).
=item batan2()
my $y = Math::BigFloat->new(2);
my $x = Math::BigFloat->new(3);
print $y->batan2($x), "\n";
Calculate the arcus tanges of C<$y> divided by C<$x>, modifying $y in place.
See also L.
This method was added in v1.87 of Math::BigInt (June 2007).
=item as_float()
This method is called when Math::BigFloat encounters an object it doesn't know
how to handle. For instance, assume $x is a Math::BigFloat, or subclass
thereof, and $y is defined, but not a Math::BigFloat, or subclass thereof. If
you do
$x -> badd($y);
$y needs to be converted into an object that $x can deal with. This is done by
first checking if $y is something that $x might be upgraded to. If that is the
case, no further attempts are made. The next is to see if $y supports the
method C. The method C is expected to return either an
object that has the same class as $x, a subclass thereof, or a string that
C[new()> can parse to create an object.
In Math::BigFloat, C has the same effect as C.
=item to_ieee754()
Encodes the invocand as a byte string in the given format as specified in IEEE
754-2008. Note that the encoded value is the nearest possible representation of
the value. This value might not be exactly the same as the value in the
invocand.
# $x = 3.1415926535897932385
$x = Math::BigFloat -> bpi(30);
$b = $x -> to_ieee754("binary64"); # encode as 8 bytes
$h = unpack "H*", $b; # "400921fb54442d18"
# 3.141592653589793115997963...
$y = Math::BigFloat -> from_ieee754($h, "binary64");
All binary formats in IEEE 754-2008 are accepted. For convenience, som aliases
are recognized: "half" for "binary16", "single" for "binary32", "double" for
"binary64", "quadruple" for "binary128", "octuple" for "binary256", and
"sexdecuple" for "binary512".
See also L.
=back
=head2 ACCURACY AND PRECISION
See also: L.
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.
Since things like C 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.
If there is no global precision or accuracy set, B the operation in
question was not called with a requested precision or accuracy, B the
input $x has no accuracy or precision set, then a fallback parameter will
be used. For historical reasons, it is called C and can be accessed
via:
$d = Math::BigFloat->div_scale(); # query
Math::BigFloat->div_scale($n); # set to $n digits
The default value for C is 40.
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:
$x = Math::BigFloat->new(2);
Math::BigFloat->accuracy(5); # 5 digits max
$y = $x->copy()->bdiv(3); # gives 0.66667
$y = $x->copy()->bdiv(3,6); # gives 0.666667
$y = $x->copy()->bdiv(3,6,undef,'odd'); # gives 0.666667
Math::BigFloat->round_mode('zero');
$y = $x->copy()->bdiv(3,6); # will also give 0.666667
Note that C<< Math::BigFloat->accuracy() >> and C<< Math::BigFloat->precision() >>
set the global variables, and thus B newly created number will be subject
to the global rounding B. This means that in the examples above, the
C<3> as argument to C will also get an accuracy of B<5>.
It is less confusing to either calculate the result fully, and afterwards
round it explicitly, or use the additional parameters to the math
functions like so:
use Math::BigFloat;
$x = Math::BigFloat->new(2);
$y = $x->copy()->bdiv(3);
print $y->bround(5),"\n"; # gives 0.66667
or
use Math::BigFloat;
$x = Math::BigFloat->new(2);
$y = $x->copy()->bdiv(3,5); # gives 0.66667
print "$y\n";
=head2 Rounding
=over
=item bfround ( +$scale )
Rounds to the $scale'th place left from the '.', counting from the dot.
The first digit is numbered 1.
=item bfround ( -$scale )
Rounds to the $scale'th place right from the '.', counting from the dot.
=item bfround ( 0 )
Rounds to an integer.
=item bround ( +$scale )
Preserves accuracy to $scale digits from the left (aka significant digits) and
pads the rest with zeros. If the number is between 1 and -1, the significant
digits count from the first non-zero after the '.'
=item bround ( -$scale ) and bround ( 0 )
These are effectively no-ops.
=back
All rounding functions take as a second parameter a rounding mode from one of
the following: 'even', 'odd', '+inf', '-inf', 'zero', 'trunc' or 'common'.
The default rounding mode is 'even'. By using
C<< Math::BigFloat->round_mode($round_mode); >> you can get and set the default
mode for subsequent rounding. The usage of C<$Math::BigFloat::$round_mode> is
no longer supported.
The second parameter to the round functions then overrides the default
temporarily.
The C function returns a BigInt from a Math::BigFloat. It uses
'trunc' as rounding mode to make it equivalent to:
$x = 2.5;
$y = int($x) + 2;
You can override this by passing the desired rounding mode as parameter to
C:
$x = Math::BigFloat->new(2.5);
$y = $x->as_number('odd'); # $y = 3
=head1 NUMERIC LITERALS
After C.
=item btmod()
$x->btmod($y); # modulus
Returns the remainer after truncated division (T-division). See L.
=item bmodinv()
$x->bmodinv($mod); # modular multiplicative inverse
Returns the multiplicative inverse of C<$x> modulo C<$mod>. If
$y = $x -> copy() -> bmodinv($mod)
then C<$y> is the number closest to zero, and with the same sign as C<$mod>,
satisfying
($x * $y) % $mod = 1 % $mod
If C<$x> and C<$y> are non-zero, they must be relative primes, i.e.,
C. 'C' is returned when no modular multiplicative
inverse exists.
=item bmodpow()
$num->bmodpow($exp,$mod); # modular exponentiation
# ($num**$exp % $mod)
Returns the value of C<$num> taken to the power C<$exp> in the modulus
C<$mod> using binary exponentiation. C is far superior to
writing
$num ** $exp % $mod
because it is much faster - it reduces internal variables into
the modulus whenever possible, so it operates on smaller numbers.
C also supports negative exponents.
bmodpow($num, -1, $mod)
is exactly equivalent to
bmodinv($num, $mod)
=item bpow()
$x->bpow($y); # power of arguments (x ** y)
C (and the rounding functions) now modifies the first argument and
returns it, unlike the old code which left it alone and only returned the
result. This is to be consistent with C etc. The first three modifies
$x, the last one won't:
print bpow($x,$i),"\n"; # modify $x
print $x->bpow($i),"\n"; # ditto
print $x **= $i,"\n"; # the same
print $x ** $i,"\n"; # leave $x alone
The form C<$x **= $y> is faster than C<$x = $x ** $y;>, though.
=item blog()
$x->blog($base, $accuracy); # logarithm of x to the base $base
If C<$base> is not defined, Euler's number (e) is used:
print $x->blog(undef, 100); # log(x) to 100 digits
=item bexp()
$x->bexp($accuracy); # calculate e ** X
Calculates the expression C where C is Euler's number.
This method was added in v1.82 of Math::BigInt (April 2007).
See also L.
=item bnok()
$x->bnok($y); # x over y (binomial coefficient n over k)
Calculates the binomial coefficient n over k, also called the "choose"
function, which is
( n ) n!
| | = --------
( k ) k!(n-k)!
when n and k are non-negative. This method implements the full Kronenburg
extension (Kronenburg, M.J. "The Binomial Coefficient for Negative Arguments."
18 May 2011. http://arxiv.org/abs/1105.3689/) illustrated by the following
pseudo-code:
if n >= 0 and k >= 0:
return binomial(n, k)
if k >= 0:
return (-1)^k*binomial(-n+k-1, k)
if k <= n:
return (-1)^(n-k)*binomial(-k-1, n-k)
else
return 0
The behaviour is identical to the behaviour of the Maple and Mathematica
function for negative integers n, k.
=item buparrow()
=item uparrow()
$a -> buparrow($n, $b); # modifies $a
$x = $a -> uparrow($n, $b); # does not modify $a
This method implements Knuth's up-arrow notation, where $n is a non-negative
integer representing the number of up-arrows. $n = 0 gives multiplication, $n =
1 gives exponentiation, $n = 2 gives tetration, $n = 3 gives hexation etc. The
following illustrates the relation between the first values of $n.
See L.
=item backermann()
=item ackermann()
$m -> backermann($n); # modifies $a
$x = $m -> ackermann($n); # does not modify $a
This method implements the Ackermann function:
/ n + 1 if m = 0
A(m, n) = | A(m-1, 1) if m > 0 and n = 0
\ A(m-1, A(m, n-1)) if m > 0 and n > 0
Its value grows rapidly, even for small inputs. For example, A(4, 2) is an
integer of 19729 decimal digits.
See https://en.wikipedia.org/wiki/Ackermann_function
=item bsin()
my $x = Math::BigInt->new(1);
print $x->bsin(100), "\n";
Calculate the sine of $x, modifying $x in place.
In Math::BigInt, unless upgrading is in effect, the result is truncated to an
integer.
This method was added in v1.87 of Math::BigInt (June 2007).
=item bcos()
my $x = Math::BigInt->new(1);
print $x->bcos(100), "\n";
Calculate the cosine of $x, modifying $x in place.
In Math::BigInt, unless upgrading is in effect, the result is truncated to an
integer.
This method was added in v1.87 of Math::BigInt (June 2007).
=item batan()
my $x = Math::BigFloat->new(0.5);
print $x->batan(100), "\n";
Calculate the arcus tangens of $x, modifying $x in place.
In Math::BigInt, unless upgrading is in effect, the result is truncated to an
integer.
This method was added in v1.87 of Math::BigInt (June 2007).
=item batan2()
my $x = Math::BigInt->new(1);
my $y = Math::BigInt->new(1);
print $y->batan2($x), "\n";
Calculate the arcus tangens of C<$y> divided by C<$x>, modifying $y in place.
In Math::BigInt, unless upgrading is in effect, the result is truncated to an
integer.
This method was added in v1.87 of Math::BigInt (June 2007).
=item bsqrt()
$x->bsqrt(); # calculate square root
C returns the square root truncated to an integer.
If you want a better approximation of the square root, then use:
$x = Math::BigFloat->new(12);
Math::BigFloat->precision(0);
Math::BigFloat->round_mode('even');
print $x->copy->bsqrt(),"\n"; # 4
Math::BigFloat->precision(2);
print $x->bsqrt(),"\n"; # 3.46
print $x->bsqrt(3),"\n"; # 3.464
=item broot()
$x->broot($N);
Calculates the N'th root of C<$x>.
=item bfac()
$x->bfac(); # factorial of $x
Returns the factorial of C<$x>, i.e., $x*($x-1)*($x-2)*...*2*1, the product of
all positive integers up to and including C<$x>. C<$x> must be > -1. The
factorial of N is commonly written as N!, or N!1, when using the multifactorial
notation.
=item bdfac()
$x->bdfac(); # double factorial of $x
Returns the double factorial of C<$x>, i.e., $x*($x-2)*($x-4)*... C<$x> must be
> -2. The double factorial of N is commonly written as N!!, or N!2, when using
the multifactorial notation.
=item btfac()
$x->btfac(); # triple factorial of $x
Returns the triple factorial of C<$x>, i.e., $x*($x-3)*($x-6)*... C<$x> must be
> -3. The triple factorial of N is commonly written as N!!!, or N!3, when using
the multifactorial notation.
=item bmfac()
$x->bmfac($k); # $k'th multifactorial of $x
Returns the multi-factorial of C<$x>, i.e., $x*($x-$k)*($x-2*$k)*... C<$x> must
be > -$k. The multi-factorial of N is commonly written as N!K.
=item bfib()
$F = $n->bfib(); # a single Fibonacci number
@F = $n->bfib(); # a list of Fibonacci numbers
In scalar context, returns a single Fibonacci number. In list context, returns
a list of Fibonacci numbers. The invocand is the last element in the output.
The Fibonacci sequence is defined by
F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2)
In list context, F(0) and F(n) is the first and last number in the output,
respectively. For example, if $n is 12, then C<< @F = $n->bfib() >> returns the
following values, F(0) to F(12):
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144
The sequence can also be extended to negative index n using the re-arranged
recurrence relation
F(n-2) = F(n) - F(n-1)
giving the bidirectional sequence
n -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7
F(n) 13 -8 5 -3 2 -1 1 0 1 1 2 3 5 8 13
If $n is -12, the following values, F(0) to F(12), are returned:
0, 1, -1, 2, -3, 5, -8, 13, -21, 34, -55, 89, -144
=item blucas()
$F = $n->blucas(); # a single Lucas number
@F = $n->blucas(); # a list of Lucas numbers
In scalar context, returns a single Lucas number. In list context, returns a
list of Lucas numbers. The invocand is the last element in the output.
The Lucas sequence is defined by
L(0) = 2
L(1) = 1
L(n) = L(n-1) + L(n-2)
In list context, L(0) and L(n) is the first and last number in the output,
respectively. For example, if $n is 12, then C<< @L = $n->blucas() >> returns
the following values, L(0) to L(12):
2, 1, 3, 4, 7, 11, 18, 29, 47, 76, 123, 199, 322
The sequence can also be extended to negative index n using the re-arranged
recurrence relation
L(n-2) = L(n) - L(n-1)
giving the bidirectional sequence
n -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7
L(n) 29 -18 11 -7 4 -3 1 2 1 3 4 7 11 18 29
If $n is -12, the following values, L(0) to L(-12), are returned:
2, 1, -3, 4, -7, 11, -18, 29, -47, 76, -123, 199, -322
=item brsft()
$x->brsft($n); # right shift $n places in base 2
$x->brsft($n, $b); # right shift $n places in base $b
The latter is equivalent to
$x -> bdiv($b -> copy() -> bpow($n))
=item blsft()
$x->blsft($n); # left shift $n places in base 2
$x->blsft($n, $b); # left shift $n places in base $b
The latter is equivalent to
$x -> bmul($b -> copy() -> bpow($n))
=back
=head2 Bitwise methods
=over
=item band()
$x->band($y); # bitwise and
=item bior()
$x->bior($y); # bitwise inclusive or
=item bxor()
$x->bxor($y); # bitwise exclusive or
=item bnot()
$x->bnot(); # bitwise not (two's complement)
Two's complement (bitwise not). This is equivalent to, but faster than,
$x->binc()->bneg();
=back
=head2 Rounding methods
=over
=item round()
$x->round($A,$P,$round_mode);
Round $x to accuracy C<$A> or precision C<$P> using the round mode
C<$round_mode>.
=item bround()
$x->bround($N); # accuracy: preserve $N digits
Rounds $x to an accuracy of $N digits.
=item bfround()
$x->bfround($N);
Rounds to a multiple of 10**$N. Examples:
Input N Result
123456.123456 3 123500
123456.123456 2 123450
123456.123456 -2 123456.12
123456.123456 -3 123456.123
=item bfloor()
$x->bfloor();
Round $x towards minus infinity, i.e., set $x to the largest integer less than
or equal to $x.
=item bceil()
$x->bceil();
Round $x towards plus infinity, i.e., set $x to the smallest integer greater
than or equal to $x).
=item bint()
$x->bint();
Round $x towards zero.
=back
=head2 Other mathematical methods
=over
=item bgcd()
$x -> bgcd($y); # GCD of $x and $y
$x -> bgcd($y, $z, ...); # GCD of $x, $y, $z, ...
Returns the greatest common divisor (GCD).
=item blcm()
$x -> blcm($y); # LCM of $x and $y
$x -> blcm($y, $z, ...); # LCM of $x, $y, $z, ...
Returns the least common multiple (LCM).
=back
=head2 Object property methods
=over
=item sign()
$x->sign();
Return the sign, of $x, meaning either C<+>, C<->, C<-inf>, C<+inf> or NaN.
If you want $x to have a certain sign, use one of the following methods:
$x->babs(); # '+'
$x->babs()->bneg(); # '-'
$x->bnan(); # 'NaN'
$x->binf(); # '+inf'
$x->binf('-'); # '-inf'
=item digit()
$x->digit($n); # return the nth digit, counting from right
If C<$n> is negative, returns the digit counting from left.
=item digitsum()
$x->digitsum();
Computes the sum of the base 10 digits and returns it.
=item bdigitsum()
$x->bdigitsum();
Computes the sum of the base 10 digits and assigns the result to the invocand.
=item length()
$x->length();
($xl, $fl) = $x->length();
Returns the number of digits in the decimal representation of the number. In
list context, returns the length of the integer and fraction part. For
Math::BigInt objects, the length of the fraction part is always 0.
The following probably doesn't do what you expect:
$c = Math::BigInt->new(123);
print $c->length(),"\n"; # prints 30
It prints both the number of digits in the number and in the fraction part
since print calls C in list context. Use something like:
print scalar $c->length(),"\n"; # prints 3
=item mantissa()
$x->mantissa();
Return the signed mantissa of $x as a Math::BigInt.
=item exponent()
$x->exponent();
Return the exponent of $x as a Math::BigInt.
=item parts()
$x->parts();
Returns the significand (mantissa) and the exponent as integers. In
Math::BigFloat, both are returned as Math::BigInt objects.
=item sparts()
Returns the significand (mantissa) and the exponent as integers. In scalar
context, only the significand is returned. The significand is the integer with
the smallest absolute value. The output of C corresponds to the
output from C.
In Math::BigInt, this method is identical to C.
=item nparts()
Returns the significand (mantissa) and exponent corresponding to normalized
notation. In scalar context, only the significand is returned. For finite
non-zero numbers, the significand's absolute value is greater than or equal to
1 and less than 10. The output of C corresponds to the output from
C. In Math::BigInt, if the significand can not be represented as an
integer, upgrading is performed or NaN is returned.
=item eparts()
Returns the significand (mantissa) and exponent corresponding to engineering
notation. In scalar context, only the significand is returned. For finite
non-zero numbers, the significand's absolute value is greater than or equal to
1 and less than 1000, and the exponent is a multiple of 3. The output of
C corresponds to the output from C. In Math::BigInt, if the
significand can not be represented as an integer, upgrading is performed or NaN
is returned.
=item dparts()
Returns the integer part and the fraction part. If the fraction part can not be
represented as an integer, upgrading is performed or NaN is returned. The
output of C corresponds to the output from C.
=item fparts()
Returns the smallest possible numerator and denominator so that the numerator
divided by the denominator gives back the original value. For finite numbers,
both values are integers. Mnemonic: fraction.
=item numerator()
Together with L, returns the smallest integers so that the
numerator divided by the denominator reproduces the original value. With
Math::BigInt, numerator() simply returns a copy of the invocand.
=item denominator()
Together with L, returns the smallest integers so that the
numerator divided by the denominator reproduces the original value. With
Math::BigInt, denominator() always returns either a 1 or a NaN.
=back
=head2 String conversion methods
=over
=item bstr()
Returns a string representing the number using decimal notation. In
Math::BigFloat, the output is zero padded according to the current accuracy or
precision, if any of those are defined.
=item bsstr()
Returns a string representing the number using scientific notation where both
the significand (mantissa) and the exponent are integers. The output
corresponds to the output from C.
123 is returned as "123e+0"
1230 is returned as "123e+1"
12300 is returned as "123e+2"
12000 is returned as "12e+3"
10000 is returned as "1e+4"
=item bnstr()
Returns a string representing the number using normalized notation, the most
common variant of scientific notation. For finite non-zero numbers, the
absolute value of the significand is greater than or equal to 1 and less than
10. The output corresponds to the output from C.
123 is returned as "1.23e+2"
1230 is returned as "1.23e+3"
12300 is returned as "1.23e+4"
12000 is returned as "1.2e+4"
10000 is returned as "1e+4"
=item bestr()
Returns a string representing the number using engineering notation. For finite
non-zero numbers, the absolute value of the significand is greater than or
equal to 1 and less than 1000, and the exponent is a multiple of 3. The output
corresponds to the output from C.
123 is returned as "123e+0"
1230 is returned as "1.23e+3"
12300 is returned as "12.3e+3"
12000 is returned as "12e+3"
10000 is returned as "10e+3"
=item bdstr()
Returns a string representing the number using decimal notation. The output
corresponds to the output from C.
123 is returned as "123"
1230 is returned as "1230"
12300 is returned as "12300"
12000 is returned as "12000"
10000 is returned as "10000"
=item to_hex()
$x->to_hex();
Returns a hexadecimal string representation of the number. See also from_hex().
=item to_bin()
$x->to_bin();
Returns a binary string representation of the number. See also from_bin().
=item to_oct()
$x->to_oct();
Returns an octal string representation of the number. See also from_oct().
=item to_bytes()
$x = Math::BigInt->new("1667327589");
$s = $x->to_bytes(); # $s = "cafe"
Returns a byte string representation of the number using big endian byte
order. The invocand must be a non-negative, finite integer. See also from_bytes().
=item to_base()
$x = Math::BigInt->new("250");
$x->to_base(2); # returns "11111010"
$x->to_base(8); # returns "372"
$x->to_base(16); # returns "fa"
Returns a string representation of the number in the given base. If a collation
sequence is given, the collation sequence determines which characters are used
in the output.
Here are some more examples
$x = Math::BigInt->new("16")->to_base(3); # returns "121"
$x = Math::BigInt->new("44027")->to_base(36); # returns "XYZ"
$x = Math::BigInt->new("58314")->to_base(42); # returns "Why"
$x = Math::BigInt->new("4")->to_base(2, "-|"); # returns "|--"
See from_base() for information and examples.
=item to_base_num()
Converts the given number to the given base. This method is equivalent to
C<_to_base()>, but returns numbers in an array rather than characters in a
string. In the output, the first element is the most significant. Unlike
C<_to_base()>, all input values may be arbitrarily large.
$x = Math::BigInt->new(13);
$x->to_base_num(2); # returns [1, 1, 0, 1]
$x = Math::BigInt->new(65191);
$x->to_base_num(128); # returns [3, 125, 39]
=item as_hex()
$x->as_hex();
As, C, but with a "0x" prefix.
=item as_bin()
$x->as_bin();
As, C, but with a "0b" prefix.
=item as_oct()
$x->as_oct();
As, C, but with a "0" prefix.
=item as_bytes()
This is just an alias for C.
=back
=head2 Other conversion methods
=over
=item numify()
print $x->numify();
Returns a Perl scalar from $x. It is used automatically whenever a scalar is
needed, for instance in array index operations.
=back
=head2 Utility methods
These utility methods are made public
=over
=item dec_str_to_dec_flt_str()
Takes a string representing any valid number using decimal notation and converts
it to a string representing the same number using decimal floating point
notation. The output consists of five parts joined together: the sign of the
significand, the absolute value of the significand as the smallest possible
integer, the letter "e", the sign of the exponent, and the absolute value of the
exponent. If the input is invalid, nothing is returned.
$str2 = $class -> dec_str_to_dec_flt_str($str1);
Some examples
Input Output
31400.00e-4 +314e-2
-0.00012300e8 -123e+2
0 +0e+0
=item hex_str_to_dec_flt_str()
Takes a string representing any valid number using hexadecimal notation and
converts it to a string representing the same number using decimal floating
point notation. The output has the same format as that of
L.
$str2 = $class -> hex_str_to_dec_flt_str($str1);
Some examples
Input Output
0xff +255e+0
Some examples
=item oct_str_to_dec_flt_str()
Takes a string representing any valid number using octal notation and converts
it to a string representing the same number using decimal floating point
notation. The output has the same format as that of
L.
$str2 = $class -> oct_str_to_dec_flt_str($str1);
=item bin_str_to_dec_flt_str()
Takes a string representing any valid number using binary notation and converts
it to a string representing the same number using decimal floating point
notation. The output has the same format as that of
L.
$str2 = $class -> bin_str_to_dec_flt_str($str1);
=item dec_str_to_dec_str()
Takes a string representing any valid number using decimal notation and converts
it to a string representing the same number using decimal notation. If the
number represents an integer, the output consists of a sign and the absolute
value. If the number represents a non-integer, the output consists of a sign,
the integer part of the number, the decimal point ".", and the fraction part of
the number without any trailing zeros. If the input is invalid, nothing is
returned.
=item hex_str_to_dec_str()
Takes a string representing any valid number using hexadecimal notation and
converts it to a string representing the same number using decimal notation. The
output has the same format as that of L.
=item oct_str_to_dec_str()
Takes a string representing any valid number using octal notation and converts
it to a string representing the same number using decimal notation. The
output has the same format as that of L.
=item bin_str_to_dec_str()
Takes a string representing any valid number using binary notation and converts
it to a string representing the same number using decimal notation. The output
has the same format as that of L.
=back
=head1 ACCURACY and PRECISION
Math::BigInt and Math::BigFloat have full support for accuracy and precision
based rounding, both automatically after every operation, as well as manually.
This section describes the accuracy/precision handling in Math::BigInt and
Math::BigFloat as it used to be and as it is now, complete with an explanation
of all terms and abbreviations.
Not yet implemented things (but with correct description) are marked with '!',
things that need to be answered are marked with '?'.
In the next paragraph follows a short description of terms used here (because
these may differ from terms used by others people or documentation).
During the rest of this document, the shortcuts A (for accuracy), P (for
precision), F (fallback) and R (rounding mode) are be used.
=head2 Precision P
Precision is a fixed number of digits before (positive) or after (negative) the
decimal point. For example, 123.45 has a precision of -2. 0 means an integer
like 123 (or 120). A precision of 2 means at least two digits to the left of
the decimal point are zero, so 123 with P = 1 becomes 120. Note that numbers
with zeros before the decimal point may have different precisions, because 1200
can have P = 0, 1 or 2 (depending on what the initial value was). It could also
have p < 0, when the digits after the decimal point are zero.
The string output (of floating point numbers) is padded with zeros:
Initial value P A Result String
------------------------------------------------------------
1234.01 -3 1000 1000
1234 -2 1200 1200
1234.5 -1 1230 1230
1234.001 1 1234 1234.0
1234.01 0 1234 1234
1234.01 2 1234.01 1234.01
1234.01 5 1234.01 1234.01000
For Math::BigInt objects, no padding occurs.
=head2 Accuracy A
Number of significant digits. Leading zeros are not counted. A number may have
an accuracy greater than the non-zero digits when there are zeros in it or
trailing zeros. For example, 123.456 has A of 6, 10203 has 5, 123.0506 has 7,
123.45000 has 8 and 0.000123 has 3.
The string output (of floating point numbers) is padded with zeros:
Initial value P A Result String
------------------------------------------------------------
1234.01 3 1230 1230
1234.01 6 1234.01 1234.01
1234.1 8 1234.1 1234.1000
For Math::BigInt objects, no padding occurs.
=head2 Fallback F
When both A and P are undefined, this is used as a fallback accuracy when
dividing numbers.
=head2 Rounding mode R
When rounding a number, different 'styles' or 'kinds' of rounding are possible.
(Note that random rounding, as in Math::Round, is not implemented.)
=head3 Directed rounding
These round modes always round in the same direction.
=over
=item 'trunc'
Round towards zero. Remove all digits following the rounding place, i.e.,
replace them with zeros. Thus, 987.65 rounded to tens (P=1) becomes 980, and
rounded to the fourth significant digit becomes 987.6 (A=4). 123.456 rounded to
the second place after the decimal point (P=-2) becomes 123.46. This
corresponds to the IEEE 754 rounding mode 'roundTowardZero'.
=back
=head3 Rounding to nearest
These rounding modes round to the nearest digit. They differ in how they
determine which way to round in the ambiguous case when there is a tie.
=over
=item 'even'
Round towards the nearest even digit, e.g., when rounding to nearest integer,
-5.5 becomes -6, 4.5 becomes 4, but 4.501 becomes 5. This corresponds to the
IEEE 754 rounding mode 'roundTiesToEven'.
=item 'odd'
Round towards the nearest odd digit, e.g., when rounding to nearest integer,
4.5 becomes 5, -5.5 becomes -5, but 5.501 becomes 6. This corresponds to the
IEEE 754 rounding mode 'roundTiesToOdd'.
=item '+inf'
Round towards plus infinity, i.e., always round up. E.g., when rounding to the
nearest integer, 4.5 becomes 5, -5.5 becomes -5, and 4.501 also becomes 5. This
corresponds to the IEEE 754 rounding mode 'roundTiesToPositive'.
=item '-inf'
Round towards minus infinity, i.e., always round down. E.g., when rounding to
the nearest integer, 4.5 becomes 4, -5.5 becomes -6, but 4.501 becomes 5. This
corresponds to the IEEE 754 rounding mode 'roundTiesToNegative'.
=item 'zero'
Round towards zero, i.e., round positive numbers down and negative numbers up.
E.g., when rounding to the nearest integer, 4.5 becomes 4, -5.5 becomes -5, but
4.501 becomes 5. This corresponds to the IEEE 754 rounding mode
'roundTiesToZero'.
=item 'common'
Round away from zero, i.e., round to the number with the largest absolute
value. E.g., when rounding to the nearest integer, -1.5 becomes -2, 1.5 becomes
2 and 1.49 becomes 1. This corresponds to the IEEE 754 rounding mode
'roundTiesToAway'.
=back
The handling of A & P in MBI/MBF (the old core code shipped with Perl versions
<= 5.7.2) is like this:
=over
=item Precision
* bfround($p) is able to round to $p number of digits after the decimal
point
* otherwise P is unused
=item Accuracy (significant digits)
* bround($a) rounds to $a significant digits
* only bdiv() and bsqrt() take A as (optional) parameter
+ other operations simply create the same number (bneg etc), or
more (bmul) of digits
+ rounding/truncating is only done when explicitly calling one
of bround or bfround, and never for Math::BigInt (not implemented)
* bsqrt() simply hands its accuracy argument over to bdiv.
* the documentation and the comment in the code indicate two
different ways on how bdiv() determines the maximum number
of digits it should calculate, and the actual code does yet
another thing
POD:
max($Math::BigFloat::div_scale,length(dividend)+length(divisor))
Comment:
result has at most max(scale, length(dividend), length(divisor)) digits
Actual code:
scale = max(scale, length(dividend)-1,length(divisor)-1);
scale += length(divisor) - length(dividend);
So for lx = 3, ly = 9, scale = 10, scale will actually be 16 (10
So for lx = 3, ly = 9, scale = 10, scale will actually be 16
(10+9-3). Actually, the 'difference' added to the scale is cal-
culated from the number of "significant digits" in dividend and
divisor, which is derived by looking at the length of the man-
tissa. Which is wrong, since it includes the + sign (oops) and
actually gets 2 for '+100' and 4 for '+101'. Oops again. Thus
124/3 with div_scale=1 will get you '41.3' based on the strange
assumption that 124 has 3 significant digits, while 120/7 will
get you '17', not '17.1' since 120 is thought to have 2 signif-
icant digits. The rounding after the division then uses the
remainder and $y to determine whether it must round up or down.
? I have no idea which is the right way. That's why I used a slightly more
? simple scheme and tweaked the few failing testcases to match it.
=back
This is how it works now:
=over
=item Setting/Accessing
* You can set the A global via Math::BigInt->accuracy() or
Math::BigFloat->accuracy() or whatever class you are using.
* You can also set P globally by using Math::SomeClass->precision()
likewise.
* Globals are classwide, and not inherited by subclasses.
* to undefine A, use Math::SomeClass->accuracy(undef);
* to undefine P, use Math::SomeClass->precision(undef);
* Setting Math::SomeClass->accuracy() clears automatically
Math::SomeClass->precision(), and vice versa.
* To be valid, A must be > 0, P can have any value.
* If P is negative, this means round to the P'th place to the right of the
decimal point; positive values mean to the left of the decimal point.
P of 0 means round to integer.
* to find out the current global A, use Math::SomeClass->accuracy()
* to find out the current global P, use Math::SomeClass->precision()
* use $x->accuracy() respective $x->precision() for the local
setting of $x.
* Please note that $x->accuracy() respective $x->precision()
return eventually defined global A or P, when $x's A or P is not
set.
=item Creating numbers
* When you create a number, you can give the desired A or P via:
$x = Math::BigInt->new($number,$A,$P);
* Only one of A or P can be defined, otherwise the result is NaN
* If no A or P is give ($x = Math::BigInt->new($number) form), then the
globals (if set) will be used. Thus changing the global defaults later on
will not change the A or P of previously created numbers (i.e., A and P of
$x will be what was in effect when $x was created)
* If given undef for A and P, NO rounding will occur, and the globals will
NOT be used. This is used by subclasses to create numbers without
suffering rounding in the parent. Thus a subclass is able to have its own
globals enforced upon creation of a number by using
$x = Math::BigInt->new($number,undef,undef):
use Math::BigInt::SomeSubclass;
use Math::BigInt;
Math::BigInt->accuracy(2);
Math::BigInt::SomeSubclass->accuracy(3);
$x = Math::BigInt::SomeSubclass->new(1234);
$x is now 1230, and not 1200. A subclass might choose to implement
this otherwise, e.g. falling back to the parent's A and P.
=item Usage
* If A or P are enabled/defined, they are used to round the result of each
operation according to the rules below
* Negative P is ignored in Math::BigInt, since Math::BigInt objects never
have digits after the decimal point
* Math::BigFloat uses Math::BigInt internally, but setting A or P inside
Math::BigInt as globals does not tamper with the parts of a Math::BigFloat.
A flag is used to mark all Math::BigFloat numbers as 'never round'.
=item Precedence
* It only makes sense that a number has only one of A or P at a time.
If you set either A or P on one object, or globally, the other one will
be automatically cleared.
* If two objects are involved in an operation, and one of them has A in
effect, and the other P, this results in an error (NaN).
* A takes precedence over P (Hint: A comes before P).
If neither of them is defined, nothing is used, i.e. the result will have
as many digits as it can (with an exception for bdiv/bsqrt) and will not
be rounded.
* There is another setting for bdiv() (and thus for bsqrt()). If neither of
A or P is defined, bdiv() will use a fallback (F) of $div_scale digits.
If either the dividend's or the divisor's mantissa has more digits than
the value of F, the higher value will be used instead of F.
This is to limit the digits (A) of the result (just consider what would
happen with unlimited A and P in the case of 1/3 :-)
* bdiv will calculate (at least) 4 more digits than required (determined by
A, P or F), and, if F is not used, round the result
(this will still fail in the case of a result like 0.12345000000001 with A
or P of 5, but this can not be helped - or can it?)
* Thus you can have the math done by on Math::Big* class in two modi:
+ never round (this is the default):
This is done by setting A and P to undef. No math operation
will round the result, with bdiv() and bsqrt() as exceptions to guard
against overflows. You must explicitly call bround(), bfround() or
round() (the latter with parameters).
Note: Once you have rounded a number, the settings will 'stick' on it
and 'infect' all other numbers engaged in math operations with it, since
local settings have the highest precedence. So, to get SaferRound[tm],
use a copy() before rounding like this:
$x = Math::BigFloat->new(12.34);
$y = Math::BigFloat->new(98.76);
$z = $x * $y; # 1218.6984
print $x->copy()->bround(3); # 12.3 (but A is now 3!)
$z = $x * $y; # still 1218.6984, without
# copy would have been 1210!
+ round after each op:
After each single operation (except for testing like is_zero()), the
method round() is called and the result is rounded appropriately. By
setting proper values for A and P, you can have all-the-same-A or
all-the-same-P modes. For example, Math::Currency might set A to undef,
and P to -2, globally.
?Maybe an extra option that forbids local A & P settings would be in order,
?so that intermediate rounding does not 'poison' further math?
=item Overriding globals
* you will be able to give A, P and R as an argument to all the calculation
routines; the second parameter is A, the third one is P, and the fourth is
R (shift right by one for binary operations like badd). P is used only if
the first parameter (A) is undefined. These three parameters override the
globals in the order detailed as follows, i.e. the first defined value
wins:
(local: per object, global: global default, parameter: argument to sub)
+ parameter A
+ parameter P
+ local A (if defined on both of the operands: smaller one is taken)
+ local P (if defined on both of the operands: bigger one is taken)
+ global A
+ global P
+ global F
* bsqrt() will hand its arguments to bdiv(), as it used to, only now for two
arguments (A and P) instead of one
=item Local settings
* You can set A or P locally by using $x->accuracy() or
$x->precision()
and thus force different A and P for different objects/numbers.
* Setting A or P this way immediately rounds $x to the new value.
* $x->accuracy() clears $x->precision(), and vice versa.
=item Rounding
* the rounding routines will use the respective global or local settings.
bround() is for accuracy rounding, while bfround() is for precision
* the two rounding functions take as the second parameter one of the
following rounding modes (R):
'even', 'odd', '+inf', '-inf', 'zero', 'trunc', 'common'
* you can set/get the global R by using Math::SomeClass->round_mode()
or by setting $Math::SomeClass::round_mode
* after each operation, $result->round() is called, and the result may
eventually be rounded (that is, if A or P were set either locally,
globally or as parameter to the operation)
* to manually round a number, call $x->round($A,$P,$round_mode);
this will round the number by using the appropriate rounding function
and then normalize it.
* rounding modifies the local settings of the number:
$x = Math::BigFloat->new(123.456);
$x->accuracy(5);
$x->bround(4);
Here 4 takes precedence over 5, so 123.5 is the result and $x->accuracy()
will be 4 from now on.
=item Default values
* R: 'even'
* F: 40
* A: undef
* P: undef
=item Remarks
* The defaults are set up so that the new code gives the same results as
the old code (except in a few cases on bdiv):
+ Both A and P are undefined and thus will not be used for rounding
after each operation.
+ round() is thus a no-op, unless given extra parameters A and P
=back
=head1 Infinity and Not a Number
While Math::BigInt has extensive handling of inf and NaN, certain quirks
remain.
=over
=item oct()/hex()
These perl routines currently (as of Perl v.5.8.6) cannot handle passed inf.
te@linux:~> perl -wle 'print 2 ** 3333'
Inf
te@linux:~> perl -wle 'print 2 ** 3333 == 2 ** 3333'
1
te@linux:~> perl -wle 'print oct(2 ** 3333)'
0
te@linux:~> perl -wle 'print hex(2 ** 3333)'
Illegal hexadecimal digit 'I' ignored at -e line 1.
0
The same problems occur if you pass them Math::BigInt->binf() objects. Since
overloading these routines is not possible, this cannot be fixed from
Math::BigInt.
=back
=head1 INTERNALS
You should neither care about nor depend on the internal representation; it
might change without notice. Use B method calls like C<< $x->sign(); >>
instead relying on the internal representation.
=head2 MATH LIBRARY
The mathematical computations are performed by a backend library. It is not
required to specify which backend library to use, but some backend libraries
are much faster than the default library.
=head3 The default library
The default library is L, which is implemented in pure Perl
and hence does not require a compiler.
=head3 Specifying a library
The simple case
use Math::BigInt;
is equivalent to saying
use Math::BigInt try => 'Calc';
You can use a different backend library with, e.g.,
use Math::BigInt try => 'GMP';
which attempts to load the L library, and falls back to the
default library if the specified library can't be loaded.
Multiple libraries can be specified by separating them by a comma, e.g.,
use Math::BigInt try => 'GMP,Pari';
If you request a specific set of libraries and do not allow fallback to the
default library, specify them using "only",
use Math::BigInt only => 'GMP,Pari';
If you prefer a specific set of libraries, but want to see a warning if the
fallback library is used, specify them using "lib",
use Math::BigInt lib => 'GMP,Pari';
The following first tries to find Math::BigInt::Foo, then Math::BigInt::Bar, and
if this also fails, reverts to Math::BigInt::Calc:
use Math::BigInt try => 'Foo,Math::BigInt::Bar';
=head3 Which library to use?
B: General purpose packages should not be explicit about the library to
use; let the script author decide which is best.
L, L, and L are in
cases involving big numbers much faster than L. However
these libraries are slower when dealing with very small numbers (less than about
20 digits) and when converting very large numbers to decimal (for instance for
printing, rounding, calculating their length in decimal etc.).
So please select carefully what library you want to use.
Different low-level libraries use different formats to store the numbers, so
mixing them won't work. You should not depend on the number having a specific
internal format.
See the respective math library module documentation for further details.
=head3 Loading multiple libraries
The first library that is successfully loaded is the one that will be used. Any
further attempts at loading a different module will be ignored. This is to avoid
the situation where module A requires math library X, and module B requires math
library Y, causing modules A and B to be incompatible. For example,
use Math::BigInt; # loads default "Calc"
use Math::BigFloat only => "GMP"; # ignores "GMP"
=head2 SIGN
The sign is either '+', '-', 'NaN', '+inf' or '-inf'.
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 get '+inf' when dividing a positive number by 0, and '-inf'
when dividing any negative number by 0.
=head1 EXAMPLES
use Math::BigInt;
sub bigint { Math::BigInt->new(shift); }
$x = Math::BigInt->bstr("1234") # string "1234"
$x = "$x"; # same as bstr()
$x = Math::BigInt->bneg("1234"); # Math::BigInt "-1234"
$x = Math::BigInt->babs("-12345"); # Math::BigInt "12345"
$x = Math::BigInt->bnorm("-0.00"); # Math::BigInt "0"
$x = bigint(1) + bigint(2); # Math::BigInt "3"
$x = bigint(1) + "2"; # ditto ("2" becomes a Math::BigInt)
$x = bigint(1); # Math::BigInt "1"
$x = $x + 5 / 2; # Math::BigInt "3"
$x = $x ** 3; # Math::BigInt "27"
$x *= 2; # Math::BigInt "54"
$x = Math::BigInt->new(0); # Math::BigInt "0"
$x--; # Math::BigInt "-1"
$x = Math::BigInt->badd(4,5) # Math::BigInt "9"
print $x->bsstr(); # 9e+0
Examples for rounding:
use Math::BigFloat;
use Test::More;
$x = Math::BigFloat->new(123.4567);
$y = Math::BigFloat->new(123.456789);
Math::BigFloat->accuracy(4); # no more A than 4
is ($x->copy()->bround(),123.4); # even rounding
print $x->copy()->bround(),"\n"; # 123.4
Math::BigFloat->round_mode('odd'); # round to odd
print $x->copy()->bround(),"\n"; # 123.5
Math::BigFloat->accuracy(5); # no more A than 5
Math::BigFloat->round_mode('odd'); # round to odd
print $x->copy()->bround(),"\n"; # 123.46
$y = $x->copy()->bround(4),"\n"; # A = 4: 123.4
print "$y, ",$y->accuracy(),"\n"; # 123.4, 4
Math::BigFloat->accuracy(undef); # A not important now
Math::BigFloat->precision(2); # P important
print $x->copy()->bnorm(),"\n"; # 123.46
print $x->copy()->bround(),"\n"; # 123.46
Examples for converting:
my $x = Math::BigInt->new('0b1'.'01' x 123);
print "bin: ",$x->as_bin()," hex:",$x->as_hex()," dec: ",$x,"\n";
=head1 NUMERIC LITERALS
After C]