Math-BigInt-2.005003/ 0000755 4030723 4001001 00000000000 14776770432 013755 5 ustar OSPJA Domain Users Math-BigInt-2.005003/BUGS 0000644 4030723 4001001 00000004266 14546553333 014442 0 ustar OSPJA Domain Users For 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 and limitations:
* 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.
* BigRat:
+ BigRat does not handle modify() yet or in a very incomplete manner
+ There are probably many... rats.
+ inf handling (partial)
+ NaN handling (partial)
+ rounding (not implemented except for bceil/bfloor)
+ $x ** $y where $y is not an integer
+ bmod(), blog(), bmodinv() and bmodpow() (partial)
###############################################################################
Mixing of classes does not always work like expected. "use bignum;",
"use bigint;", "use bigfloat", 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!
Math-BigInt-2.005003/CHANGES 0000644 4030723 4001001 00000363637 14776675370 014777 0 ustar OSPJA Domain Users 2.005003 2025-04-13
* Add new methods to_fp80() and from_fp80() for encoding and decoding values in
the x86 extended-precision 80 bit format.
2.005002 2025-03-28
* Fix the handling of read-only objects in bblsft() and bbrsft() in
Math::BigFloat and Math::BigRat.
2.005001 2025-03-25
New:
* Add new method bperm() to Math::BigInt, Math::BigFloat, and Math::BigRat.
* Add the following methods to Math::BigRat and Math::BigFloat:
bilog2(), bilog10(), bclog2(), bclog10(), bfib(), blucas(),
from_bytes(), from_base(), to_bytes(), to_ieee754()
* Add method bmuladd(), bgcd(), and blcm() to Math::BigRat.
* Add method bpi() to Math::BigRat. It returns a rational approximation of PI
accurate to the specified accuracy or precision, or the default accuracy if
no accuracy is specified.
* Add methods bdstr(), bnstr(), and bestr() to Math::BigRat.
* Add support for rounding in Math::BigFloat methods bdstr(), bestr(), bnstr(),
and bestr().
* Add method from_ieee754() to Math::BigInt and Math::BigRat, including
documentation. In Math::BigInt, from_ieee754() is similar to the other
from_xxx() methods in that way that it returns a NaN if the input is a finite
non-integer.
* Add new backend library method _scmp() for doing signed comparison.
Changes/Improvements:
* Method new() now always returns a new object, as would be expected.
* Make bgcd() in Math::BigRat and Math::BigFloat support non-integer arguments.
Now, bgcd(0.8, 1.2) in Math::BigFloat returns 0.4, and bgcd(4/5, 6/5) in
Math::BigRat returns 2/5.
* Make blcm(0, 0) work the same way in Math::BigInt, Math::BigRat, and
Math::BigFloat. Now blcm(0, 0) is always 0.
* Correct the documentation for is_inf(), bceil() and bfloor()
* Methods bdiv() and bmod() are now aliases to bfdiv() and bfmod(),
respectively. (This doesn't change the behaviour of bdiv() and bmod().)
* Math::BigFloat methods bfmod() and btmod() are faster than before.
* Improve documentation for bnok().
* Improve upgrading and downgrading, e.g., use $class->upgrade() rather than
just $upgrade, since the former works better for sublasses.
Fixes:
* Add missing calls to modify().
* All boolean methods now return 1 or 0. Some would return 1 or "".
* Harmonise methods in different classes so they behave similarly, at least to
the extent possible.
* Fix bug in Math::BigInt->bfib() causing sign to be incorrect for some of the
output values when bfib() was called in list context with a negative input.
* Correct miscellaneous typos and errors in the documentation.
2.004001 2025-02-12
* Improve upgrading and downgrading.
- Upgrading and downgrading is more consistent.
- Upgrading and downgrading now keeps the reference, so in the following
example, $x changes from being a Math::BigInt with a value of 2 to a
Math::BigFloat with the value 1.4142...
perl -Mbignum -le '$x = 2; $x -> bsqrt(); print $x'
* Fix bug in Math::BigFloat->bdiv(): in list context, bdiv() would do floored
division, except when the denominator was 1. Now, bdiv() always does floored
division.
2.003004 2025-01-23
* Fix CPAN RT #150252 regarding bdiv() not modifying the invocand object when
upgrading/downgrading is enabled.
* Add hyperoperator method bhyperop(). This method implements succession,
addition, multiplication, exponentiation, tetration, pentation ...).
2.003003 2024-05-27
* Fix CPAN RT #153736 regarding bnok() with large input values.
2.003002 2024-01-05
* Improved interaction between Math::BigInt and the backend libraries.
* Much faster versions of _ilog2() and _clog2() implemented in the
Math::BigInt::Calc backend library. This should speed up bilog2() and
bclog2() in Math::BigInt when "Calc" is used as the backend liberary.
2.003001 2023-12-26
* Add configuration methods trap_inf() and trap_nan(). Previously it was only
possible to modify these properties by using the config() method.
* Fix CPAN RT #150796 so that config() no longer modifies the input when it is
a hash ref.
* Fix CPAN RT #150797 so that both accuracy and precision can be set
simultaneously with config().
* Add the following methods to Math::BigInt
- bilog2() base 2 logarithm rounded downwards, i.e., int(log2(x))
- bilog10() base 10 logarithm rounded downwards, i.e., int(log10(x))
- bclog2() base 2 logarithm rounded upwards, i.e., ceil(log2(x))
- bclog10() base 10 logarithm rounded upwards, i.e., ceil(log10(x))
* Add the following backend library methods to Math::BigInt::Lib. These
methods do the core computations for the corresponding methods in
Math::BigInt (see above).
- _ilog2() base 2 logarithm rounded downwards
- _ilog10() base 10 logarithm rounded downwards
- _clog2() base 2 logarithm rounded upwards
- _clog10() base 10 logarithm rounded upwards
2.002001 2023-12-09
* Fix CPAN RT #150523
2.002000 2023-12-02
* Fix bug in Math::BigFloat method bsin(). It can now handle any argument to
any precision. Also improve downgrading. This fixes CPAN RT #150590 and the
bsin() part of CPAN RT #107604.
* Fix bug in Math::BigFloat method bexp(). Specifying precision (rather than
accuracy) used to give a NaN. Also improve downgrading.
* Improve upgrading in Math::BigInt methods bsin() and bcos(). They now
upgrade only when necessary.
2.001001 2023-11-21
* Fix CPAN RT #150469
2.001000 2023-11-13
* Fix rounding bug in bsqrt() in Math::BigInt. Also make bsqrt() upgrade only
when necessary.
* Simplify and speed up bsqrt() (for computing the square root) in
Math::BigFloat. The computation time now mainly depends on the desired
accuracy, not the number of digits in the significand.
* Add support for using "div_scale" as import parameter, like this
use Math::BigFloat div_scale => 80;
* Add better argument checking when the "div_scale" value is set by the
user.
2.000000 2023-10-29
* Merge the Math-BigRat distribution into the Math-BigInt distribution. This
merge eliminates the problems that users have experienced when incompatible
versions of the two distributions have been installed. This fixes CPAN RT
#143228.
* Add method from_dec() to Math::BigRat to make Math::BigRat more consistent
with Math::BigInt and Math::BigFloat.
* To be consistent with Math::BigInt and Math::BigFloat, make it possible to
use "require" with Math::BigRat, e.g.,
require Math::BigRat;
$x = Math::BigRat -> bone();
* Fix cases where "require" doesn't work for Math::BigInt and Math::BigFloat,
and add tests to verify that "require" works for Math::BigInt, Math::BigRat,
and Math::BigFloat.
* Add methods bblsft() and bbrsft() to Math::BigRat to make Math::BigRat
consistent with Math::BigInt and Math::BigFloat. These methods do bitwise
left and right shift, respectively.
* Fix bug in to_oct() and to_bin() in Math::BigFloat. They called to_hex()
when upgrading, but should have called to_oct() and to_bin(), respectively.
* Add to_hex(), to_oct(), to_bin() to Math::BigRat.
* Add new method binv() to Math::BigInt, Math::BigFloat, and Math::BigRat.
* Improve as_float() and as_rat().
* POD updates.
1.999842 2023-09-27
* Fix a bug causing Math::BigInt and Math::BigFloat to be caught in an endless
recursion. The bug was introduced when trying to fix
https://github.com/pjacklam/p5-Math-BigInt/issues/8
* Allow div_scale to be 0. It is not documented what div_scale <= 0 means, but
there are modules that set div_scale to 0 (e.g., Astro::Units) and fail
their tests if this is not supported.
1.999841 2023-09-21
* Remove development files that were accidentally included in the
distribution.
1.999840 2023-09-18
* Add methods bblsft() and bbrsft(), which do bitwise left and right shift,
respectively. The binary operators for bitwise left and right shift, "<<"
and ">>", now call the methods bblsft() and bbrsft(), respectively.
While this behaviour is consistent with how "<<" and ">>" work on floating
point numbers in core Perl, it changes how "<<" and ">>" worked on
Math::BigFloat objects. This is a corner case, but any code currently using
"<<" and ">>" on Math::BigFloat objects might need to be modified as follows
$x >>= $y should be changed to $x -> brsft($y)
$x <<= $y should be changed to $x -> blsft($y)
$x >> $y should be changed to $x -> copy() -> brsft($y)
$x << $y should be changed to $x -> copy() -> blsft($y)
* Improve blsft() and brsft(). They now support negative shift values, an
arbitrarily large base, and have better handling of cases involving NaN.
1.999839 2023-07-14
* Update documentation. Remove/update obsolete URLs.
* Fix CPAN RT #148953 regarding loss of precision when using "log" in
"bignum". The issue was related to broken upgrading and downgrading in
Math::BigFloat.
1.999838 2023-03-30
* Fix CPAN RT #146411 regarding infinite recursion in bitwise operations. This
happened when arguments were upgraded and downgraded and upgraded again ad
infinitum. Add tests to verify the fix.
1.999837 2022-07-02
* Improve the interoperability between objects of different classes for the
methods that are still used as functions.
1.999836 2022-06-24
* Improve compatibility with older versions of the Math-BigRat distribution.
Math-BigInt version 1.999835 works with Math-BigRat version 0.2623 and newer.
Math-BigInt version 1.999836 works with Math-BigRat version 0.2618 and newer.
* Re-enable upgrading in Math::BigFloat->bdiv().
* Fix an error in the enabling/disabling of upgrading/downgrading.
* Fix typos and other formatting errors.
1.999835 2022-05-24
* Fix bug related to upgrading in Math::BigInt->brsft(). This bug
only showed up in Perl versions 5.16 and older.
1.999834 2022-05-23
* Further improvements to upgrading and downgrading.
1.999833 2022-05-23
* Fix Math::BigFloat->bpi(). The previous attempt at correcting it
wasn't sufficient. Added test to verify the fix.
* Correct the formatting in the CHANGES file.
1.999832 2022-05-21
* Improve as_int(), as_float(), and as_rat() so that they return a
Math::BigInt, Math::BigFloat, and Math::BigRat, respectivly,
regardless of upgrading and downgrading.
* Improve stringification method bsstr() so that it handles upgrading
and downgrading better.
* Fix Math::BigFloat->bpi(), which unfortunately didn't handle
downgrading.
* Avoid unnecessary downgrading/upgrading.
* Add missed cases where downgrading/upgrading should be performed.
* Avoid unnecessary stringification.
1.999831 2022-05-16
* Further improvements to upgrading, downgrading, and rounding.
* New stringification method bfstr() for representing numbers as fractions.
E.g., Math::BigFloat -> new("1.25") -> bfstr() returns "5/4".
* Miscellaneous bug fixes.
* Fixed errors and typos in the documentation.
1.999830 2022-04-11
* Improve upgrading and downgrading. This work is not complete. Some methods
still don't downgrade when they should.
1.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).
If you just want to see which things are new and different from the original
Math::* in the Perl core, see HISTORY.
In earlier versions of the distribution, each module had a separate changelog:
##############################################################################
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::BigRat:
0.2624 2022-06-27
* Improve stringification. Better handling of upgrading/downgrading in
stringification methods. Add new method bfstr() for compatibility with
Math::BigInt og Math::BigFloat. Add new author test files to confirm.
0.2623 2022-05-16
* Fix rounding issues.
0.2622 2022-04-13
* Add more cases for downgrading, and more tests.
0.2621 2022-04-11
* Improve downgrading and upgrading.
0.2620 2021-10-03
* Skip tests that don't work on older Perls. Also skip tests that compare
floating point numbers.
0.2619 2021-10-01
* Correct the handling of Inf and NaN in numify().
* Improve constant overloading. When numeric constants are overloaded
(with the ":constant" option) in Math::BigRat, every numeric constant
is converted to an object regardless of how it is written.
0.2618 2021-09-28
* Add new method binv() for the inverse.
* Add new method dparts(), which returns the integer part and fraction part
of a number. For example, 9/4 is split into 2 and 1/4. This method is
equivalent to the Math::BigInt and Math::BigFloat methods with the same
name.
* Improve blog(). Handle cases $x->blog($b) where the numerator of $x
and/or $b is 1 as special.
* Sync tests with Math-BigInt.
0.2617 2021-07-12
* Fix CPAN RT #132712.
* Reorganize existing test files and add more test files.
0.2616 2021-07-12
* Improve the handling of the backend libraries.
0.2615 2021-07-10
* Fix bnok(). It didn't work at all.
* Fix minor POD error (CPAN RT #125148).
* Better Makefile.PL.
* Update the BUGS and SUPPORT sections in the POD.
* Update README.
0.2614 2018-04-17
* Fix bug in bpow() (CPAN RT #124002). Add tests to verify fix.
* Fix bug in is_one(). The code $x->is_one("-") returned false when $x was -1
and true when $x was 1. Add tests to verify fix.
* Improve bsqrt() so it returns the exact result when possible.
* Fix documentation errors.
* The tests now require Test::More version 0.88 or newer.
* Add test files t/release-portability.t, t/release-test-version.t, and
t/release-cpan-changes.t.
* Update TODO file.
* Prefer as_int() to as_number(), since what is does is return an integer.
* Expand tabs to spaces and clean up whitepace.
* 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.
* Better testing of NaN and Inf trapping.
* Use $class->config("xyz") rather than $class->config()->{xyz}.
* Add more tests of is_inf() to catch bugs like the one that was in is_one().
Specifically, make sure we test is_inf() with and without a sign argument.
* Use $LIB for the math backend library class.
* Reformat test data in t/bigratpm.inc.
* Import carp() and croak() from Carp.
* Make tests pass when '.' is not in @INC (CPAN RT #120892).
* Remove t/bigroot.t and t/biglog.t which didn't test Math::BigRat at all.
0.2613 2017-06-16 pjacklam
* Fix problem with second operand being changed in multiplication (CPAN RT
#121139).
0.2612 2017-03-01 pjacklam
* Improve the logic in blog() to determine how to call objectify(). The old,
simpler logic didn't handle an undefined base correctly.
* Fix bexp() which was objectifying one argument too many.
* Don't quote the version number of a use'd module.
0.2611 2016-12-13 pjacklam
* Add more logic to Makefile.PL regarding INSTALLDIRS (CPAN RT #119199
and #119225).
0.2610 2016-12-11 pjacklam
* Fix Makefile.PL so that this module installs over the core version.
0.2609 2016-12-03 pjacklam
* Use ExtUtils::MakeMaker rather than Module::Install in Makefile.PL
* Remove INSTALL file. The information is in the README file.
* Inform in the BUGS file that the file may not be up to date.
* Inform in the TODO file that the file may not be up to date.
* Update AUTHOR information in Math/BigRat.pm.
* Remove author information in LICENSE file.
* Update README file.
* Minor POD reformatting in lib/Math/BigRat.pm.
0.260805 2016-11-15 pjacklam
* Standardize on using $LIB for the variable holding the class of the backend
library.
* Improve bmul() by doing _gcd() twice on smaller numbers rather than once on
larger numbers.
0.260804 2016-04-25 pjacklam
* Revert the change to the 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.
* Overloaded 'int' should not modify it's argument.
* The first output argument from objectify() is the class name, so use the
variable name $class, not $self.
* In Makefile.PL, change "build_requires 'Test::More' => 0.47" to
"test_requires 'Test::More' => 0.47". Test::More is only needed for testing,
not for building.
0.260803 2016-04-22 pjacklam
* Add methods bnan(), binf(), bzero(), and bone(). The old code was based on
an undocumented behaviour where the superclass made assumptions about the
subclass.
* Fix tests where ok() was used incorrectly, like ok($got, $expected).
* Remove "require Carp", since we have "use Carp" in the heading.
* Completly rewrite new(). It was buggy and hard to maintain.
* Add more descriptions to tests.
* Rename blog-mbr.t to author-blog-mbr.t.
* Simplify bsqrt() and blog(). Don't assume we know the internals of
Math::BigFloat objects.
* Change bmodpow() and bmodinv() so they handle all input arguments.
Non-integers are truncated to integers.
* Change internals of bnok().
* as_float() and numify() should not make assumptions about the internals of
Math::BigFloat objects.
* Wrap long lines.
* Fix typo in POD ("conversation" -> "conversion").
* Make internal functions _new_from_float() and _new_from_int() redundant and
remove them. They make assumtions about the internals of Math::BigFloat
objects and Math::BigInt objects, respectively.
* Make internal function _as_float() redundant and remove it.
* Add methods band(), bior(), bxor(), and bnot().
0.260802 2015-12-28 pjacklam
* Fix blog(). The handling of inf and NaN was broken. It also returned
incorrect result in several cases, especially when both the operand and the
base were both integers. In some cases, the correct result was returned,
but the operand was not set to this value. An undefined base (indicating
that Euler's number e should be used) was not handled correctly.
* Update author information in Makefile.PL.
* Add tests for log() in t/bigratpm.inc as well as templates for the other
overloaded functions exp, sin, cos, atan2, int, abs, and sqrt.
* Update number of tests in t/bigratpm.t.
* Add test file t/blog-mbr.t.
* Reformat tests and add comments/descriptions to them.
* Accept both "Inf" and "Infinity", ignoring letter case, and letting the
sign be optional. This matches the current behaviour of core Perl.
* Internal clean-up of the copy() method.
* Remove all occurences of "require Carp", since we "use Carp".
* Reformat some of the code to make the code more readable (for me, at least)
and more in accordance with the guidelines in the "perlstyle" man page.
* Correct some errors in the comments in the code.
* Use "our ..." rather than "use vars ...".
* Rename variables so they have more descriptive names and are more in
accordance with the Math-BigInt distribution.
* Remove unused variables.
* Use "use lib 't'" rather than "unshift @INC, 't'".
* Include "use strict" and "use warnings" in all files.
0.260801 2015-09-14 pjacklam
* Added support for bdiv() in list context. Added corresponding tests.
* Changed bmod() so the result corresponds to Perl's % operator, as well as
the second output argument of bdiv() in list contest. Modified tests
correspondingly. Now the behaviour of bmod() is consistent between
Math::BigInt, Math::BigFloat, and Math::BigRat.
* Clearer POD for the bdiv() and bmod() methods.
* Display more information about loaded modules.
0.2608 2015-08-28 pjacklam
* Wrap long lines.
* Increment version number. (Sync with blead.)
0.2607 2015-08-28 pjacklam
* Add changes from v0.2602 to v0.2606.
* Increment version number. (Sync with blead.)
* Update bundled version of Module::Install from v1.08 to v1.16.
0.2606 2014-04-03 pjacklam
* Add ref to https://rt.cpan.org/Public/Dist/Display.html?Name=Math-BigRat
* Misc. updates.
* Update bundled version of Module::Install from v1.00 to v1.08.
* Fix spelling errors.
* Avoid negative zero.
* Various POD corrections.
* Add refereces to CPAN testers, CPAN RT etc.
* Test to avoid negative zero.
0.2602 2011-02-13 pjacklam (1000 tests)
* Fix spelling errors (Peter John Acklam).
* Include latest versions test scripts shared with the Math::BigInt
distribution (Peter John Acklam).
* Add 00sig.t for testing the SIGNATURE file, 01load.t for explicitly
testing module loading and showing version information useful for
debugging (Peter John Acklam).
* Replace pod.t and pod_cov.t by 02pod.t as a generic script for testing
POD syntax, and 03podcov.t as a more generic script for testing POD
coverage (Peter John Acklam).
0.26 2010-09-15 rafl 975 tests
* Remove obsolete test boilerplate that was once needed to test within the
perl core (Nicholas Clark).
* Convert tests from Test to Test::More (Nicholas Clark).
0.25 2010-09-13 rafl 975 tests
* Re-upload 0.24 with a fixed SIGNATURE
0.24 2009-09-09 Leto 975 tests
* Fix [perl RT #49565: SIGNATURES]
* Fix [perl RT #44827: Documentation incorrect]
0.23 2009-09-08 Leto 975 tests
* Fix [perl RT #67244] hex "e" misunderstood by Math::BigRat
0.22 2008-04-06 Tels 973 tests
* fix bug ##34584: hang when calling exp (Thanx Steve Wills!)
+ broot() normalizes result
+ bexp() works for values like '1/2' (sqrt), '1/4' (broot), etc.
+ broot() works for values like '2/3'
* added as_float() - return the BigRat as rounded Math::BigFloat
0.21 2007-09-16 Tels 956 tests
* require Math::BigInt v1.88
* fix as_number() with Nan/inf (thanx zefram!)
* add POD stub for objectify() to make pod_cov.t happy
0.20 2007-06-30 Tels 956 tests
* require Math::BigInt v1.87
* add bnok() and bexp()
0.19 2007-04-17 Tels 934 tests
* fix the check in bnorm() as it breaks under Pari
* require Math::BigInt v1.83
* exponent() makes a copy, so we can skip copy()
* fix the licence back to be "perl"
0.18 2007-04-09 Tels 934 tests
* install_as_core() to work around Module::Install bug
* remove PREREQ_FATAL since the toolchain is broken
* require Math::BigInt v1.82
0.17 2007-02-03 Tels 934 tests
* include the spelling fixes for bleadperl
* more typo and POD fixes
* include from_bin(), from_hex() and from_oct()
* add tests for octal and from_hex()/from_bin()
* bundle and use Module::Install
0.16 2007-01-28 Tels 926 tests
* require Math::BigInt 1.78
* add support for 'try' and 'only'
* add pod tests
0.15 2005-04-02 Tels 924 tests
* no need to require Exporter
* rem no longer used 'with' from import
* add a few comments here and there
* fix import()'s handling of the lib argument (it didn't work)
* fix segfault under trap_nan in _bnan()
* remove unused IMPORT logic (require BigRat seems to work without it)
0.14 2005-01-01 Tels 924 tests
* require Math::BigInt v1.74
* streamline copy()
* inline is_zero() into bneg(), making it about 50% faster
* more tests for bneg()
* register callback to get notified of lib changes from Math::BigInt
* much simpler import() logic
* new() accepts input like new(Math::BigInt->new(123),Math::BigInt->new(7));
* doc: as_hex(), as_bin(), add note about as_pos(), as_neg() and as_int()
* numify() now deals with large N and D by using BigFloat (Thanx Hugo!)
* numify() lost the sign on negative integer values (Thanx Zefram!)
0.13 2004-10-22 Tels 892 tests
* fixed digit(): it never worked due to dropping the second parameter
* fixed a bug in brsft() when passing arguments (2 vs. 3 in objectify)
* use Math::BigInt->config('lib') for parts instead of Math::BigInt
+ This makes everything go about 2..4 times faster :)
+ And it saves memory (408 vs. 807 bytes for a simple number)
* _as_float() is about 6 times as fast for integers (e.g. 123/1 vs. 2/3)
* denominator() returns 1 for +inf and -inf (+inf/1, -inf/1) instead of +-inf
* when using "lib => GMP;", certain things never worked:
+ sqrt() was not possible
+ new("2.3") did not work
+ new("12.3e-2") did not work
0.12 2004-02-15 Tels 863 tests
* fixed bug in is_one() (segfault under v.5.6.x)
* implemented length() and digit() for integers
* beefed up testing class Test.pm to make more float tests work (185 of them
still fail)
* added AUTOLOAD to load fxxx() stubs (for BigFloat compatibility tests)
* $IMPORT for require and AUTOLOAD
* added as_bin(), as_hex() which work for integers, NaN, and +-inf
* implement broot() and blog() for non-integer numbers
* fixed blsft()/brsft() to work with undefined or scalar base
* added a copy() method to be independend from BigInt's copy()
* adopted to new internal format of Math::BigFloat v1.44 (from BigInt v1.70)
0.11 2004-01-07 Tels 859 tests
* require Exporter vs. use it
* more tests for bacmp(), bnorm()
* fixed bug in bacmp() with ($x,[+-]inf) (Thanx to William T. Morgan!)
* fixed bug in new("+-inf/X") (e.g. "-inf/5" resulted in "inf", not "-inf")
* delete _a and _p on _d and _n, reduces size of a BigRat object from
887 bytes to 767 bytes on a x86 32 bit system. This also makes some
operations slightly (single-digit percentages) faster.
* bacmp() is about 20% faster
* bcmp() is:
* about 4 times faster if sign($x) != sign($y)
* about 20% faster if sign($x) == sign($y)
* added broot(), bmodinv(), bmodpow(), blog() so that their equivalent of:
# perl -MMath::BigRat=:constant -le '$a = 2.0 ** 32; print $a->broot(4)'
Can't call method "copy" on an undefined value at BigFloat.pm line 1442.
works now for integer arguments and inf/NaN, at least.
* doc: rationales => rational numbers
0.10 2003-07-06 Tels 751 tests (released on 2003-08-13)
* one more die => croak conversion
* fix inf/NAN handling in new()
* fix bsqrt(3/4) and similiar cases failing with some obscure error, this was
a simple typo ({_n} vs. {_m}). Added tests for that.
* numify() is now much faster (38400 vs 720 tries/s on 2Ghz AMD XP2400+)
* support for :trap_nan/:trap_inf
* doc for config()
* implement trapping of creation of NaN/inf/-inf
* as_number() forgot to disable $upgrade, resulting in BigRat again when
run under -Mbigrat -- thanx to Ian Phillips.
* fixed a bug in new() that failed with
Math::BigRat->new(Math::BigInt::Lite->new(123));
* fixed new() to work better under
use Math::BigRat with => 'Math::BigInt::Lite';
* add a test for "require Math::BigRat; $x = Math::BigRat->new(123); $x++;"
(it already works since we "use Math::BigFloat;"
* require Carp; Carp::croak () instead of simple die()
* implemented bmod() - Thanx Ian Phillips.
* bsqrt() now returns a big rationale - Ian again
* tests for bmod(), as_number(), bsqrt() and some NaN cases
* bfloor()/bceil() broke under use bigrat; due to missing upgrade-disabling
0.09 2002-08-14 Tels
* documentation was lacking a proper description, METHODS missing etc
* setting accuracy/precision in BigFloat/BigInt interfered with BigRat
* new testcases for the A/P fix in t/big_ap.t
* speedup: apply the same trick to avoid calls to objectify() like in BigInt
* speedup: badd()/bsub() did needless gcd(), copy() and bdiv()
* speedup: workaround for 'x.y.z'-valid bug in BigFloat no longer neccessary
0.08 2002-08-13 Tels
* bsstr() returned positive result for negative numbers - Oups!
* added a numify() so that $array[Math::BigRat->new('17/8')] works
0.07 2002-06-04 Tels
* bfac() now works for integers (x/1), and returns $x->bnan() instead of
Math::BigRat->bnan() (modify in-place)
* bpow() faster for x/1 ** y/1 and x/z ** y/1 cases (some of the speedups are
two-digit factors :) - also some bugfixes
* bpow() no longer litters stdout
* removed some (all of them commented out) debug prints to reduce footprint
* shortened testfile bigrat.t
* some hardcoded 'Math::BigInt' replaced with '$MBI'
* bceil() would leave -0 in some cases
* (more) tests (all in all 628) for:
bceil/bfloor/bpow/bfac/parts/denominator/nominator/binc/bdec
* parts('-3/1') would return (3,1) instead of (-3,1)
* parts() did not work for NaN, +inf, -inf
* numerator()/denominator() did not work for inf,-inf,NaN
* new('1.2.2') was valid (resulted in 12/10 due to bug in BigFloat)
* new() for some cases left internal state not as 0/0 for NaN, inf, -inf etc
* binc()/bdec() were missing entirely
0.06 2002-05-23 Tels
* added import() routine
* support for 'use Math::BigRat with => Foo::Bar;'
* support for 'use Math::BigRat lib => Foo::Bar;'
* bnorm() makes sure that both parts (n and d) are of class $MBI
* more documentation
* bugfix in new() with two arguments
* INSTALLDIRS => perl
0.05 2002-03-26 Tels
* various bugfixes
(local undef upgrade, Bigint handling, handling of string arguments)
* fixed up isa()
* removed some old and wrong comments
0.04 2002-03-19 Tels
* 5/7+3/7 hung under "Math::BigInt upgrade =>" (forgot local upgrade = undef)
* better testsuite
* added & fixed isa()
* new() can handle Lite
0.04 2002-03-19 Tels
* bcmp/bacmp/as_number/bfloor/bceil work now
* bsqrt() is better now
* t/Math/BigInt/Test.pm is fixed now and makes a much better figure
(formerly almost all of the 1500 tests in bigfltrt.inc would fail. Now we
fail "only" 868 of 2014 tests, and most of them since the test dies early.
* added stubs for round, bfround, bround and certain others
0.03 2002-02-25 Tels (early morning hours)
* fixed bstr()/bsstr() for negative output and inf/NaN
* _d/_n were accidentily swapped
* added numerator()/denominator()/parts() and doc and tests
* fixed is_one()
* '1/ ' is as invalid as '1/'
* badd/bsub/bmul: inf/NaN handling was wrong due to copy&paste (ha!) from bdiv
* more extensive testsuite (about 400 tests)
* bnorm() normalizes 0/x to 0/1
* badd()/bsub()/bmul()/bdiv() handle +/-/NaN/inf/-inf sign properly
* t/Math/BigRat/Test.pm: fixed bstr() and bsstr() to handle inf/NaN and signs
0.02 2002-02-24 Tels (late night)
* ripped out doc and replaced by something closer to the truth
* subclass of BigFloat w/ overload section
* uses d/n instead of x/y for denominator and nominator
* tests from Math::BigFloat with a test subclass warping the input/output
* added preliminary bmul(), badd(), bdiv() methods
* added binf(), bone(), bzero() and bnan()
* added _bzero(), _bone(), _bnan() and _binf() (bnan() etc inherited)
* dummy blog(), bceil(), floor(), bfac() and bpow() functions
* parse input as '0.1', '0.1/0.1', '1/10', '10' or '10/0.1'
* input as Math::BigInts or Math::BigFloats is okay
0.01 2001-11-21 Tels
* first release
Math-BigInt-2.005003/CREDITS 0000644 4030723 4001001 00000003435 14511435771 014771 0 ustar OSPJA Domain Users I 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-2.005003/examples/ 0000755 4030723 4001001 00000000000 14776770355 015577 5 ustar OSPJA Domain Users Math-BigInt-2.005003/examples/1000.txt 0000644 4030723 4001001 00000016152 14505066124 016703 0 ustar OSPJA Domain 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-2.005003/examples/bigprimes.pl 0000755 4030723 4001001 00000010171 14505066124 020076 0 ustar OSPJA Domain 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-2.005003/examples/prime.pl 0000755 4030723 4001001 00000003661 14505066124 017237 0 ustar OSPJA Domain 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-2.005003/GOALS 0000644 4030723 4001001 00000002531 14511435771 014535 0 ustar OSPJA Domain Users This 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-2.005003/HISTORY 0000644 4030723 4001001 00000011366 14511435771 015037 0 ustar OSPJA Domain Users This 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-2.005003/lib/ 0000755 4030723 4001001 00000000000 14776770353 014525 5 ustar OSPJA Domain Users Math-BigInt-2.005003/lib/Math/ 0000755 4030723 4001001 00000000000 14776770354 015417 5 ustar OSPJA Domain Users Math-BigInt-2.005003/lib/Math/BigFloat.pm 0000644 4030723 4001001 00001017201 14776760254 017444 0 ustar OSPJA Domain Users package 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"
# _m : absolute value of mantissa ($LIB thingy)
# _es : sign of exponent ("+" or "-")
# _e : absolute value of exponent ($LIB thingy)
# accuracy : accuracy (scalar)
# precision : precision (scalar)
use 5.006001;
use strict;
use warnings;
use Carp qw< carp croak >;
use Scalar::Util qw< blessed >;
use Math::BigInt qw< >;
our $VERSION = '2.005003';
$VERSION =~ tr/_//d;
require Exporter;
our @ISA = qw< Math::BigInt >;
our @EXPORT_OK = qw< bpi >;
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]) -> bblsft($_[0])
: $_[0] -> copy() -> bblsft($_[1]); },
'>>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bbrsft($_[0])
: $_[0] -> copy() -> bbrsft($_[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] -> bblsft($_[1]); },
'>>=' => sub { $_[0] -> bbrsft($_[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'
our $accuracy = undef;
our $precision = undef;
our $round_mode = 'even';
our $div_scale = 40;
our $upgrade = undef;
our $downgrade = undef;
our $_trap_nan = 0; # croak on NaNs?
our $_trap_inf = 0; # croak on Infs?
my $nan = 'NaN'; # constant for easier life
my $LIB = Math::BigInt -> config('lib'); # math backend library
# Has import() been called yet? This variable is needed to make "require" work.
my $IMPORT = 0;
# 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
our $rnd_mode;
our $AUTOLOAD;
sub TIESCALAR {
my ($class) = @_;
bless \$round_mode, $class;
}
sub FETCH {
return $round_mode;
}
sub STORE {
$rnd_mode = (ref $_[0]) -> round_mode($_[1]);
}
BEGIN {
*objectify = \&Math::BigInt::objectify;
# 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';
*as_number = \&as_int;
}
sub DESTROY {
# going through AUTOLOAD for every DESTROY is costly, avoid it by empty sub
}
sub AUTOLOAD {
# Make fxxx() work by mapping fxxx() to Math::BigFloat::bxxx().
my $name = $AUTOLOAD;
$name =~ s/^(.*):://; # strip package name
my $class = $1 || __PACKAGE__;
$class -> import() if $IMPORT == 0;
# E.g., "fabs" -> "babs", but "is_neg" -> "is_neg"
my $bname = $name;
$bname =~ s/^f/b/;
# Map, e.g., Math::BigFloat::fabs() to Math::BigFloat::babs()
if ($bname ne $name && Math::BigFloat -> can($bname)) {
no strict 'refs';
return &{"Math::BigFloat::$bname"}(@_);
}
# Map, e.g., Math::BigFloat::babs() to Math::BigInt::babs()
elsif (Math::BigInt -> can($bname)) {
no strict 'refs';
return &{"Math::BigInt::$bname"}(@_);
}
else {
croak("Can't call $class->$name(), not a valid method");
}
}
##############################################################################
# Compare the following function with @ISA above. This inheritance mess needs a
# clean up. When doing so, also consider the BEGIN block and the AUTOLOAD code.
# Fixme!
sub isa {
my ($self, $class) = @_;
return if $class =~ /^Math::BigInt/; # we aren't one of these
UNIVERSAL::isa($self, $class);
}
sub config {
my $self = shift;
my $class = ref($self) || $self || __PACKAGE__;
# Getter/accessor.
if (@_ == 1 && ref($_[0]) ne 'HASH') {
my $param = shift;
return $class if $param eq 'class';
return $LIB if $param eq 'with';
return $self -> SUPER::config($param);
}
# Setter.
my $cfg = $self -> SUPER::config(@_);
# We need only to override the ones that are different from our parent.
unless (ref($self)) {
$cfg->{class} = $class;
$cfg->{with} = $LIB;
}
$cfg;
}
###############################################################################
# Constructor methods
###############################################################################
sub new {
# Create a new Math::BigFloat object from a string or another Math::BigInt,
# Math::BigFloat, or Math::BigRat object. See hash keys documented at top.
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Calling new() with no input arguments has been discouraged for more than
# 10 years, but 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;
# See if $wanted is an object that is a Math::BigFloat or can convert
# itself to a Math::BigFloat.
if (defined(blessed($wanted)) && $wanted -> can('as_float')) {
my $tmp = $wanted -> as_float(@r);
for my $attr ('sign', '_m', '_es', '_e') {
$self -> {$attr} = $tmp -> {$attr};
}
return $self -> round(@r);
}
# From now on we only work on the stringified version of $wanted, so
# stringify it once and for all.
$wanted = "$wanted";
# Shortcut for simple forms like '123' that have no trailing zeros.
# Trailing zeros would require a non-zero exponent.
if ($wanted =~
/ ^
\s* # optional leading whitespace
( [+-]? ) # optional sign
0* # optional leading zeros
( [1-9] (?: [0-9]* [1-9] )? ) # significand
\s* # optional trailing whitespace
$
/x)
{
my $dng = $class -> downgrade();
return $dng -> new($1 . $2) if $dng && $dng ne $class;
$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;
}
# Handle Infs.
if ($wanted =~ / ^
\s*
( [+-]? )
inf (?: inity )?
\s*
\z
/ix)
{
my $sgn = $1 || '+';
return $class -> binf($sgn, @r);
}
# Handle explicit NaNs (not the ones returned due to invalid input).
if ($wanted =~ / ^
\s*
( [+-]? )
nan
\s*
\z
/ix)
{
return $class -> bnan(@r);
}
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_flt_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_flt_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_flt_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_flt_lib_parts($wanted)
or
# See if it is an octal floating point number. The extra check is
# included because _oct_str_to_flt_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_flt_lib_parts($wanted))
{
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
$self -> round(@r)
unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
$self -> _dng() if ($self -> is_int() ||
$self -> is_inf() ||
$self -> is_nan());
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(@r);
}
sub from_dec {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('from_dec');
my $str = shift;
my @r = @_;
if (my @parts = $class -> _dec_str_to_flt_lib_parts($str)) {
# If called as a class method, initialize a new object.
unless ($selfref) {
$self = bless {}, $class;
#$self -> _init();
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
$self -> round(@r)
unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
$self -> _dng() if ($self -> is_int() ||
$self -> is_inf() ||
$self -> is_nan());
return $self;
}
return $self -> bnan(@r);
}
sub from_hex {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('from_hex');
my $str = shift;
my @r = @_;
if (my @parts = $class -> _hex_str_to_flt_lib_parts($str)) {
# If called as a class method, initialize a new object.
unless ($selfref) {
$self = bless {}, $class;
#$self -> _init();
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
$self -> round(@r)
unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
$self -> _dng() if ($self -> is_int() ||
$self -> is_inf() ||
$self -> is_nan());
return $self;
}
return $self -> bnan(@r);
}
sub from_oct {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('from_oct');
my $str = shift;
my @r = @_;
if (my @parts = $class -> _oct_str_to_flt_lib_parts($str)) {
# If called as a class method, initialize a new object.
unless ($selfref) {
$self = bless {}, $class;
#$self -> _init();
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
$self -> round(@r)
unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
$self -> _dng() if ($self -> is_int() ||
$self -> is_inf() ||
$self -> is_nan());
return $self;
}
return $self -> bnan(@r);
}
sub from_bin {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('from_bin');
my $str = shift;
my @r = @_;
if (my @parts = $class -> _bin_str_to_flt_lib_parts($str)) {
# If called as a class method, initialize a new object.
unless ($selfref) {
$self = bless {}, $class;
#$self -> _init();
}
($self->{sign}, $self->{_m}, $self->{_es}, $self->{_e}) = @parts;
$self -> round(@r)
unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
$self -> _dng() if ($self -> is_int() ||
$self -> is_inf() ||
$self -> is_nan());
return $self;
}
return $self -> bnan(@r);
}
sub from_bytes {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('from_bytes');
my $str = shift;
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero(@r) unless $selfref;
$self -> {sign} = "+";
$self -> {_m} = $LIB -> _from_bytes($str);
$self -> {_es} = "+";
$self -> {_e} = $LIB -> _zero();
$self -> bnorm();
$self -> _dng();
return $self;
}
sub from_ieee754 {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self 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 = @_; # rounding parameters, if any
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 = $class -> 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(@r);
}
}
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;
}
$self -> round(@r);
$self -> _dng() if ($self -> is_int() ||
$self -> is_inf() ||
$self -> is_nan());
return $self;
}
croak("The format '$format' is not yet supported.");
}
sub from_fp80 {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('from_fp80');
my $in = shift; # input string (or raw bytes)
my @r = @_; # rounding parameters, if any
# Undefined input.
unless (defined $in) {
carp("Input is undefined");
return $self -> bzero(@r);
}
# The parameters for this format.
my $p = 64; # precision (in bits)
my $w = 15; # number of bits in exponent
# The maximum exponent, minimum exponent, and exponent bias.
my $emax = $class -> new(2) -> bpow($w - 1) -> bdec(); # = 16383
my $emin = 1 - $emax; # = -16382
my $bias = $emax; # = -16383
# Make sure input string is a string of zeros and ones.
my $len = CORE::length $in;
if (8 * $len == 80) { # bytes
$in = unpack "B*", $in;
} elsif (4 * $len == 80) { # hexadecimal
if ($in =~ /([^\da-f])/i) {
croak "Illegal hexadecimal digit '$1'";
}
$in = unpack "B*", pack "H*", $in;
} elsif ($len == 80) { # 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
# zero and subnormal numbers
if ($expo < $emin) {
if ($mant == 0) { # zero
$x = $class -> bzero();
} else { # subnormals
# compute (1/2)**N rather than 2**(-N)
$x = $class -> new("0.5");
$x -> bpow(-$emin - 1 + $p) -> bmul($mant);
$x -> bneg() if $sign eq '-';
}
}
# inf and nan
elsif ($expo > $emax) {
# if fraction of mantissa is zero, i.e., if mantissa is
# 0.000... or 1.000...
if (substr($in, 16) =~ /^[01]0+$/) {
$x = $class -> binf($sign);
} else {
$x = $class -> bnan();
}
}
# normal numbers
else {
# downscale mantissa
$mant -> blsft($p - 1, "0.5"); # brsft($p - 1, 2) does division
if ($expo < 0) {
# compute (1/2)**N rather than 2**(-N)
$x = $mant -> blsft(-$expo, "0.5");
} elsif ($expo > 0) {
$x = $mant -> blsft($expo, "2");
} else {
$x = $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;
}
$self -> round(@r);
$self -> _dng() if ($self -> is_int() ||
$self -> is_inf() ||
$self -> is_nan());
return $self;
}
sub from_base {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('from_base');
my ($str, $base, $cs, @r) = @_; # $cs is the collation sequence
$base = $class -> new($base) unless ref($base);
croak("the base must be a finite integer >= 2")
if $base < 2 || ! $base -> is_int();
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
# If no collating sequence is given, pass some of the conversions to
# methods optimized for those cases.
unless (defined $cs) {
return $self -> from_bin($str, @r) if $base == 2;
return $self -> from_oct($str, @r) if $base == 8;
return $self -> from_hex($str, @r) if $base == 16;
return $self -> from_dec($str, @r) if $base == 10;
}
croak("from_base() requires a newer version of the $LIB library.")
unless $LIB -> can('_from_base');
my $base_lib = $LIB -> _lsft($LIB -> _copy($base->{_m}), $base->{_e}, 10);
$self -> {sign} = '+';
$self -> {_m} = $LIB->_from_base($str, $base_lib,
defined($cs) ? $cs : ());
$self -> {_es} = "+";
$self -> {_e} = $LIB->_zero();
$self -> bnorm();
$self -> bround(@r);
$self -> _dng();
return $self;
}
sub bzero {
# create/assign '+0'
# Class::method(...) -> Class->method(...)
unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
$_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i))
{
#carp "Using ", (caller(0))[3], "() as a function is deprecated;",
# " use is as a method instead";
unshift @_, __PACKAGE__;
}
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('bzero');
my $dng = $class -> downgrade();
if ($dng && $dng ne $class) {
return $self -> _dng() -> bzero(@_) if $selfref;
return $dng -> bzero(@_);
}
# Get the rounding parameters, if any.
my @r = @_;
# If called as a class method, initialize a new object.
$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.
#return $self -> round(@r); # this should work, but doesnt; fixme!
if (@r) {
if (@r >= 2 && defined($r[0]) && defined($r[1])) {
carp "can't specify both accuracy and precision";
return $self -> bnan();
}
$self->{accuracy} = $r[0];
$self->{precision} = $r[1];
} else {
unless($selfref) {
$self->{accuracy} = $class -> accuracy();
$self->{precision} = $class -> precision();
}
}
return $self;
}
sub bone {
# Create or assign '+1' (or -1 if given sign '-').
# Class::method(...) -> Class->method(...)
unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
$_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i))
{
#carp "Using ", (caller(0))[3], "() as a function is deprecated;",
# " use is as a method instead";
unshift @_, __PACKAGE__;
}
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('bone');
my $dng = $class -> downgrade();
if ($dng && $dng ne $class) {
return $self -> _dng() -> bone(@_) if $selfref;
return $dng -> bone(@_);
}
# Get the sign.
my $sign = '+'; # default is to return +1
if (defined($_[0]) && $_[0] =~ /^\s*([+-])\s*$/) {
$sign = $1;
shift;
}
# Get the rounding parameters, if any.
my @r = @_;
# If called as a class method, initialize a new object.
$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.
#return $self -> round(@r); # this should work, but doesnt; fixme!
if (@r) {
if (@r >= 2 && defined($r[0]) && defined($r[1])) {
carp "can't specify both accuracy and precision";
return $self -> bnan();
}
$self->{accuracy} = $_[0];
$self->{precision} = $_[1];
} else {
unless($selfref) {
$self->{accuracy} = $class -> accuracy();
$self->{precision} = $class -> precision();
}
}
return $self;
}
sub binf {
# create/assign a '+inf' or '-inf'
# Class::method(...) -> Class->method(...)
unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
$_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i))
{
#carp "Using ", (caller(0))[3], "() as a function is deprecated;",
# " use is 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()");
}
}
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('binf');
# Get the sign.
my $sign = '+'; # default is to return positive infinity
if (defined($_[0]) && $_[0] =~ /^\s*([+-])(inf|$)/i) {
$sign = $1;
shift;
}
# Get the rounding parameters, if any.
my @r = @_;
# Downgrade?
my $dng = $class -> downgrade();
if ($dng && $dng ne $class) {
return $self -> _dng() -> binf($sign, @r) if $selfref;
return $dng -> binf($sign, @r);
}
# If called as a class method, initialize a new object.
$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.
#return $self -> round(@r); # this should work, but doesnt; fixme!
if (@r) {
if (@r >= 2 && defined($r[0]) && defined($r[1])) {
carp "can't specify both accuracy and precision";
return $self -> bnan();
}
$self->{accuracy} = $r[0];
$self->{precision} = $r[1];
} else {
unless($selfref) {
$self->{accuracy} = $class -> accuracy();
$self->{precision} = $class -> precision();
}
}
return $self;
}
sub bnan {
# create/assign a 'NaN'
# Class::method(...) -> Class->method(...)
unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
$_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i))
{
#carp "Using ", (caller(0))[3], "() as a function is deprecated;",
# " use is 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()");
}
}
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Don't modify constant (read-only) objects.
return $self if $selfref && $self -> modify('bnan');
my $dng = $class -> downgrade();
if ($dng && $dng ne $class) {
return $self -> _dng() -> bnan(@_) if $selfref;
return $dng -> bnan(@_);
}
# Get the rounding parameters, if any.
my @r = @_;
# If called as a class method, initialize a new object.
$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.
#return $self -> round(@r); # this should work, but doesnt; fixme!
if (@r) {
if (@r >= 2 && defined($r[0]) && defined($r[1])) {
carp "can't specify both accuracy and precision";
return $self -> bnan();
}
$self->{accuracy} = $r[0];
$self->{precision} = $r[1];
} else {
unless($selfref) {
$self->{accuracy} = $class -> accuracy();
$self->{precision} = $class -> precision();
}
}
return $self;
}
sub bpi {
# Class::method(...) -> Class->method(...)
unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
$_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i))
{
#carp "Using ", (caller(0))[3], "() as a function is deprecated;",
# " use is as a method instead";
unshift @_, __PACKAGE__;
}
# 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
# Make "require" work.
$class -> import() if $IMPORT == 0;
if ($selfref) { # bpi() called as an instance method
return $self if $self -> modify('bpi');
} else { # bpi() called as a class method
$self = bless {}, $class; # initialize new instance
}
($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 = < '+',
_m => $LIB -> _new($digits),
_es => CORE::length($digits) > 1 ? '-' : '+',
_e => $LIB -> _new($n - 1),
}, $class;
} 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]);
}
$pi -> _dng() if ($pi -> is_int() ||
$pi -> is_inf() ||
$pi -> is_nan());
%$self = %$pi;
bless $self, ref($pi);
return $self;
}
sub copy {
my ($x, $class);
if (ref($_[0])) { # $y = $x -> copy()
$x = shift;
$class = ref($x);
} else { # $y = Math::BigInt -> copy($y)
$class = shift;
$x = shift;
}
carp "Rounding is not supported for ", (caller(0))[3], "()" if @_;
my $copy = bless {}, $class;
$copy->{sign} = $x->{sign};
$copy->{_es} = $x->{_es};
$copy->{_m} = $LIB->_copy($x->{_m});
$copy->{_e} = $LIB->_copy($x->{_e});
$copy->{accuracy} = $x->{accuracy} if exists $x->{accuracy};
$copy->{precision} = $x->{precision} if exists $x->{precision};
return $copy;
}
sub as_int {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Temporarily disable upgrading and downgrading.
my $upg = Math::BigInt -> upgrade();
my $dng = Math::BigInt -> downgrade();
Math::BigInt -> upgrade(undef);
Math::BigInt -> downgrade(undef);
my $y;
if ($x -> isa("Math::BigInt")) {
$y = $x -> copy();
} else {
if ($x -> is_inf()) {
$y = Math::BigInt -> binf($x -> sign());
} elsif ($x -> is_nan()) {
$y = Math::BigInt -> bnan();
} else {
$y = Math::BigInt -> new($x -> copy() -> bint() -> bdstr());
}
# Copy the remaining instance variables.
($y->{accuracy}, $y->{precision}) = ($x->{accuracy}, $x->{precision});
}
$y -> round(@r);
# Restore upgrading and downgrading.
Math::BigInt -> upgrade($upg);
Math::BigInt -> downgrade($dng);
return $y;
}
sub as_rat {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Temporarily disable upgrading and downgrading.
require Math::BigRat;
my $upg = Math::BigRat -> upgrade();
my $dng = Math::BigRat -> downgrade();
Math::BigRat -> upgrade(undef);
Math::BigRat -> downgrade(undef);
my $y;
if ($x -> isa("Math::BigRat")) {
$y = $x -> copy();
} else {
if ($x -> is_inf()) {
$y = Math::BigRat -> binf($x -> sign());
} elsif ($x -> is_nan()) {
$y = Math::BigRat -> bnan();
} else {
$y = Math::BigRat -> new($x -> bfstr());
}
# Copy the remaining instance variables.
($y->{accuracy}, $y->{precision}) = ($x->{accuracy}, $x->{precision});
}
$y -> round(@r);
# Restore upgrading and downgrading.
Math::BigRat -> upgrade($upg);
Math::BigRat -> downgrade($dng);
return $y;
}
sub as_float {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Disable upgrading and downgrading.
require Math::BigFloat;
my $upg = Math::BigFloat -> upgrade();
my $dng = Math::BigFloat -> downgrade();
Math::BigFloat -> upgrade(undef);
Math::BigFloat -> downgrade(undef);
my $y;
if ($x -> isa("Math::BigFloat")) {
$y = $x -> copy();
} else {
if ($x -> is_inf()) {
$y = Math::BigFloat -> binf($x -> sign());
} elsif ($x -> is_nan()) {
$y = Math::BigFloat -> bnan();
} else {
if ($x -> isa("Math::BigRat")) {
if ($x -> is_int()) {
$y = Math::BigFloat -> new($x -> bdstr());
} else {
my ($num, $den) = $x -> fparts();
my $str = $num -> as_float() -> bdiv($den, @r) -> bdstr();
$y = Math::BigFloat -> new($str);
}
} else {
$y = Math::BigFloat -> new($x -> bdstr());
}
}
# Copy the remaining instance variables.
($y->{accuracy}, $y->{precision}) = ($x->{accuracy}, $x->{precision});
}
$y -> round(@r);
# Restore upgrading and downgrading.
Math::BigFloat -> upgrade($upg);
Math::BigFloat -> downgrade($dng);
return $y;
}
###############################################################################
# Boolean methods
###############################################################################
sub is_zero {
# return true if arg (BFLOAT or num_str) is zero
my (undef, $x) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return 0 if $x->{sign} ne '+';
return 1 if $LIB->_is_zero($x->{_m});
return 0;
}
sub is_one {
# return true if arg (BFLOAT or num_str) is +1 or -1 if signis given
my (undef, $x, $sign) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
if (defined($sign)) {
croak 'is_one(): sign argument must be "+" or "-"'
unless $sign eq '+' || $sign eq '-';
} else {
$sign = '+';
}
return 0 if $x->{sign} ne $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 (undef, $x) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return 0 unless $x -> is_finite();
$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 (undef, $x) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return 0 unless $x -> is_finite();
($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 (undef, $x) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return 0 unless $x -> is_finite();
return $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, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Handle all 'nan' cases.
return if $x -> is_nan() || $y -> is_nan();
# Handle all '+inf' and '-inf' cases.
return 0 if ($x -> is_inf("+") && $y -> is_inf("+") ||
$x -> is_inf("-") && $y -> is_inf("-"));
return +1 if $x -> is_inf("+"); # x = +inf and y < +inf
return -1 if $x -> is_inf("-"); # x = -inf and y > -inf
return -1 if $y -> is_inf("+"); # x < +inf and y = +inf
return +1 if $y -> is_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, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# handle +-inf and NaN
if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/) {
return if ($x -> is_nan() || $y -> is_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, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bneg');
# For +0 do not negate (to have always normalized +0).
$x->{sign} =~ tr/+-/-+/
unless $x->{sign} eq '+' && $LIB->_is_zero($x->{_m});
$x -> round(@r);
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
sub bnorm {
# bnorm() can't support rounding, because bround() and bfround() call
# bnorm(), which would recurse indefinitely.
# adjust m and e so that m is smallest possible
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# inf and nan
if ($x->{sign} !~ /^[+-]$/) {
$x -> round(@r);
$x -> _dng();
return $x;
}
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 0, and -0 => +0
if ($LIB->_is_zero($x->{_m})) {
$x->{sign} = '+';
$x->{_es} = '+';
$x->{_e} = $LIB->_zero();
}
}
# Inf and NaN was handled above, so no need to check for this.
$x -> _dng() if $x -> is_int();
return $x;
}
sub binc {
# increment arg by one
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('binc');
# Inf and NaN
if ($x -> is_inf() || $x -> is_nan()) {
$x -> round(@r);
$x -> _dng();
return $x
}
# Non-integer
if ($x->{_es} eq '-') {
return $x -> badd($class -> bone(), @r);
}
# If the exponent is non-zero, convert the internal representation, so
# that, e.g., 12e+3 becomes 12000e+0 and we can easily increment the
# mantissa.
if (!$LIB->_is_zero($x->{_e})) {
$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);
}
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
sub bdec {
# decrement arg by one
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bdec');
# Inf and NaN
if ($x -> is_inf() || $x -> is_nan()) {
$x -> round(@r);
$x -> _dng();
return $x
}
# Non-integer
if ($x->{_es} eq '-') {
return $x -> badd($class -> bone('-'), @r);
}
# If the exponent is non-zero, convert the internal representation, so
# that, e.g., 12e+3 becomes 12000e+0 and we can easily increment the
# mantissa.
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();
if (($x->{sign} eq '-') || $zero) { # x <= 0
$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
$x -> bnorm();
}
elsif ($x->{sign} eq '+') { # x > 0
$x->{_m} = $LIB->_dec($x->{_m});
$x -> bnorm();
}
$x -> round(@r);
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
sub badd {
# set up parameters
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('badd');
unless ($x -> is_finite() && $y -> is_finite()) {
return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
return $x -> is_inf("+") ? ($y -> is_inf("-") ? $x -> bnan(@r)
: $x -> binf("+", @r))
: $x -> is_inf("-") ? ($y -> is_inf("+") ? $x -> bnan(@r)
: $x -> binf("-", @r))
: ($y -> is_inf("+") ? $x -> binf("+", @r)
: $x -> binf("-", @r));
}
return $x -> _upg() -> badd($y, @r) if $class -> upgrade();
$r[3] = $y; # no push!
# for speed: no add for $x + 0
if ($y -> is_zero()) {
$x -> round(@r);
}
# for speed: no add for 0 + $y
elsif ($x -> is_zero()) {
# 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;
$x -> round(@r);
}
# both $x and $y are non-zero
else {
# 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) = $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}) = $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}) {
$x->{_m} = $LIB->_add($x->{_m}, $add);
} else {
($x->{_m}, $x->{sign}) =
$LIB -> _sadd($x->{_m}, $x->{sign}, $add, $y->{sign});
}
# delete trailing zeros, then round
$x -> bnorm() -> round(@r);
}
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
sub bsub {
# set up parameters
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bsub');
$r[3] = $y; # no push!
unless ($x -> is_finite() && $y -> is_finite()) {
return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
return $x -> is_inf("+") ? ($y -> is_inf("+") ? $x -> bnan(@r)
: $x -> binf("+", @r))
: $x -> is_inf("-") ? ($y -> is_inf("-") ? $x -> bnan(@r)
: $x -> binf("-", @r))
: ($y -> is_inf("+") ? $x -> binf("-", @r)
: $x -> binf("+", @r));
}
$x -> badd($y -> copy() -> bneg(), @r);
return $x;
}
sub bmul {
# multiply two numbers
# set up parameters
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bmul');
return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
# inf handling
if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) {
return $x -> bnan(@r) 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(@r) if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
return $x -> binf(@r) if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
return $x -> binf('-', @r);
}
return $x -> _upg() -> bmul($y, @r) if $class -> upgrade();
# aEb * cEd = (a*c)E(b+d)
$x->{_m} = $LIB->_mul($x->{_m}, $y->{_m});
($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);
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
*bdiv = \&bfdiv;
*bmod = \&bfmod;
sub bfdiv {
# This does floored division (or floor division) where the quotient is
# rounded towards minus infinity.
#
# ($q, $r) = $x -> btdiv($y) returns $q and $r so that $q is floor($x / $y)
# and $q * $y + $r = $x.
# Set up parameters.
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
###########################################################################
# Code for all classes that share the common interface.
###########################################################################
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bfdiv');
my $wantarray = wantarray; # call only once
# At least one argument is NaN. 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_nan() || $y -> is_nan()) {
return $wantarray ? ($x -> bnan(@r), $class -> bnan(@r))
: $x -> bnan(@r);
}
# 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 $rem;
if ($wantarray) {
$rem = $x -> copy() -> round(@r);
$rem -> _dng() if $rem -> is_int();
}
if ($x -> is_zero()) {
$x -> bnan(@r);
} else {
$x -> binf($x->{sign}, @r);
}
return $wantarray ? ($x, $rem) : $x;
}
# 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 $rem;
$rem = $class -> bnan(@r) if $wantarray;
if ($y -> is_inf()) {
$x -> bnan(@r);
} else {
my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
$x -> binf($sign, @r);
}
return $wantarray ? ($x, $rem) : $x;
}
# 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 $rem;
if ($wantarray) {
if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
$rem = $x -> copy() -> round(@r);
$rem -> _dng() if $rem -> is_int();
$x -> bzero(@r);
} else {
$rem = $class -> binf($y -> {sign}, @r);
$x -> bone('-', @r);
}
} else {
$x -> bzero(@r);
}
return $wantarray ? ($x, $rem) : $x;
}
# At this point, both the numerator and denominator are finite, non-zero
# numbers.
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my (@params, $scale);
($x, @params) = $x->_find_round_parameters($r[0], $r[1], $r[2], $y);
if ($x -> is_nan()) { # error in _find_round_parameters?
$x -> round(@r);
return $wantarray ? ($x, $class -> bnan(@r)) : $x;
}
# 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[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
}
# Temporarily disable downgrading
my $dng = Math::BigFloat -> downgrade();
Math::BigFloat -> downgrade(undef);
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!
# Are both operands the same object, i.e., like $x -> bdiv($x)? If so,
# flipping the sign of $y also flips the sign of $x.
my $xsign = $x -> {sign};
my $ysign = $y -> {sign};
$y -> {sign} =~ tr/+-/-+/; # Flip the sign of $y, and see ...
my $same = $xsign ne $x -> {sign}; # ... if that changed the sign of $x.
$y -> {sign} = $ysign; # Re-insert the original sign.
if ($same) { # $x -> bdiv($x)
$x -> bone();
} else {
# make copy of $x in case of list context for later remainder
# calculation
$rem = $x -> copy() if $wantarray;
$x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
# promote Math::BigInt and its 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); # scale up
$x->{_m} = $LIB->_div($x->{_m}, $y->{_m}); # divide
# correct exponent of $x
($x->{_e}, $x->{_es})
= $LIB -> _ssub($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
# correct for 10**scale
($x->{_e}, $x->{_es})
= $LIB -> _ssub($x->{_e}, $x->{_es}, $LIB->_new($scale), '+');
$x -> bnorm(); # remove trailing zeros
}
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x->{accuracy} = undef; # clear before round
$x -> bround($params[0], $params[2]); # then round accordingly
} else {
$x->{precision} = undef; # 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
$x->{accuracy} = undef;
$x->{precision} = undef;
}
# Restore downgrading
Math::BigFloat -> downgrade($dng);
if ($wantarray) {
$x -> bfloor();
$rem -> bfmod($y, @params); # copy already done
if ($fallback) {
# clear a/p after round, since user did not request it
$rem->{accuracy} = undef;
$rem->{precision} = undef;
}
$x -> _dng() if $x -> is_int();
$rem -> _dng() if $rem -> is_int();
return $x, $rem;
}
$x -> _dng() if $x -> is_int();
$x; # rounding already done above
}
sub bfmod {
# (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return
# remainder
# set up parameters
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bfmod');
# At least one argument is NaN. This is handled the same way as in
# Math::BigInt -> bfmod().
return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
# Modulo zero. This is handled the same way as in Math::BigInt -> bfmod().
if ($y -> is_zero()) {
return $x -> round(@r);
}
# Numerator (dividend) is +/-inf. This is handled the same way as in
# Math::BigInt -> bfmod().
if ($x -> is_inf()) {
return $x -> bnan(@r);
}
# Denominator (divisor) is +/-inf. This is handled the same way as in
# Math::BigInt -> bfmod().
if ($y -> is_inf()) {
if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
return $x -> round(@r);
} else {
return $x -> binf($y -> sign(), @r);
}
}
# Modulo is zero if $x is zero or if $x is an integer and $y is +/-1.
return $x -> bzero(@r) if $x -> is_zero()
|| ($x -> is_int() &&
# check that $y == +1 or $y == -1:
($LIB->_is_zero($y->{_e}) && $LIB->_is_one($y->{_m})));
# Numerator (dividend) and denominator (divisor) are identical. Return
# zero.
my $cmp = $x -> bacmp($y); # $x <=> $y
if ($cmp == 0) { # $x == $y => result 0
return $x -> bzero(@r);
}
# Compare the exponents of $x and $y.
my $ecmp = $LIB->_scmp($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
my $ym = $y->{_m}; # mantissa of y, scaled if necessary
if ($ecmp > 0) {
# $x has a larger exponent than $y, so shift the mantissa of $x by the
# difference between the exponents of $x and $y.
#
# 123e+2 % 456e+1 => 1230 % 456 (+2 - +1 = 1)
# 123e+2 % 456e-1 => 123000 % 456 (+2 - -1 = 3)
# 456e-1 % 123e-3 => 12300 % 456 (-1 - -3 = 2)
# get the difference between exponents; $ds is always "+" here
my ($de, $ds) = $LIB->_ssub($LIB->_copy($x->{_e}), $x->{_es},
$y->{_e}, $y->{_es});
# adjust the mantissa of x by the difference between exponents
$x->{_m} = $LIB->_lsft($x->{_m}, $de, 10);
# compute the modulus
$x->{_m} = $LIB->_mod($x->{_m}, $ym);
# adjust the exponent of x to correct for the ajustment of the mantissa
($x->{_e}, $x->{_es}) = $LIB->_ssub($x->{_e}, $x->{_es}, $de, $ds);
} elsif ($ecmp < 0) {
# $x has a smaller exponent than $y, so shift the mantissa of $y by the
# difference between the exponents of $x and $y.
#
# 123456e+1 % 78e+2 => 123456 % 780 (+2 - +1 = 1)
# 123456e-2 % 78e+1 => 123456 % 78000 (+1 - -2 = 3)
# get the difference between exponents; $ds is always "+" here
my ($de, $ds) = $LIB->_ssub($LIB->_copy($y->{_e}), $y->{_es},
$x->{_e}, $x->{_es});
# adjust the mantissa of y by the difference between exponents
$ym = $LIB->_lsft($LIB->_copy($ym), $de, 10);
# compute the modulus
$x->{_m} = $LIB->_mod($x->{_m}, $ym);
} else {
# $x has the same exponent as $y, so compute the modulus directly
# compute the modulus
$x->{_m} = $LIB->_mod($x->{_m}, $ym);
}
if ($LIB->_is_zero($x->{_m})) {
$x->{sign} = '+';
} else {
# adjust for floored division/modulus
$x->{_m} = $LIB->_sub($ym, $x->{_m}, 1)
if $x->{sign} ne $y->{sign};
$x->{sign} = $y->{sign};
}
$x -> bnorm();
$x -> round($r[0], $r[1], $r[2], $y);
$x -> _dng() if $x -> is_int();
return $x;
}
sub btdiv {
# This does truncated division, where the quotient is truncted, i.e.,
# rounded towards zero.
#
# ($q, $r) = $x -> btdiv($y) returns $q and $r so that $q is int($x / $y)
# and $q * $y + $r = $x.
# Set up parameters
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
###########################################################################
# Code for all classes that share the common interface.
###########################################################################
# Don't modify constant (read-only) objects.
return $x if $x -> modify('btdiv');
my $wantarray = wantarray; # call only once
# At least one argument is NaN. Return NaN for both quotient and the
# modulo/remainder.
if ($x -> is_nan() || $y -> is_nan()) {
return $wantarray ? ($x -> bnan(@r), $class -> bnan(@r))
: $x -> bnan(@r);
}
# Divide by zero and modulo zero.
#
# Division: Use the common convention that x / 0 is inf with the same sign
# as x, except when x = 0, where we return NaN. This is also what earlier
# versions did.
#
# Modulo: In modular arithmetic, the congruence relation z = x (mod y)
# means that there is some integer k such that z - x = k y. If y = 0, we
# get z - x = 0 or z = x. This is also what earlier versions did, except
# that 0 % 0 returned NaN.
#
# inf / 0 = inf inf % 0 = inf
# 5 / 0 = inf 5 % 0 = 5
# 0 / 0 = NaN 0 % 0 = 0
# -5 / 0 = -inf -5 % 0 = -5
# -inf / 0 = -inf -inf % 0 = -inf
if ($y -> is_zero()) {
my $rem;
if ($wantarray) {
$rem = $x -> copy(@r);
}
if ($x -> is_zero()) {
$x -> bnan(@r);
} else {
$x -> binf($x -> {sign}, @r);
}
return $wantarray ? ($x, $rem) : $x;
}
# Numerator (dividend) is +/-inf, and denominator is finite and non-zero.
# The divide by zero cases are covered above. In all of the cases listed
# below we return the same as core Perl.
#
# inf / -inf = NaN inf % -inf = NaN
# inf / -5 = -inf inf % -5 = NaN
# inf / 5 = inf inf % 5 = NaN
# inf / inf = NaN inf % inf = NaN
#
# -inf / -inf = NaN -inf % -inf = NaN
# -inf / -5 = inf -inf % -5 = NaN
# -inf / 5 = -inf -inf % 5 = NaN
# -inf / inf = NaN -inf % inf = NaN
if ($x -> is_inf()) {
my $rem;
$rem = $class -> bnan(@r) if $wantarray;
if ($y -> is_inf()) {
$x -> bnan(@r);
} else {
my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
$x -> binf($sign,@r );
}
return $wantarray ? ($x, $rem) : $x;
}
# Denominator (divisor) is +/-inf. The cases when the numerator is +/-inf
# are covered above. In the modulo cases (in the right column) we return
# the same as core Perl, which does floored division, so for consistency we
# also do floored division in the division cases (in the left column).
#
# -5 / inf = 0 -5 % inf = -5
# 0 / inf = 0 0 % inf = 0
# 5 / inf = 0 5 % inf = 5
#
# -5 / -inf = 0 -5 % -inf = -5
# 0 / -inf = 0 0 % -inf = 0
# 5 / -inf = 0 5 % -inf = 5
if ($y -> is_inf()) {
my $rem;
if ($wantarray) {
$rem = $x -> copy() -> round(@r);
$rem -> _dng() if $rem -> is_int();
}
$x -> bzero(@r);
return $wantarray ? ($x, $rem) : $x;
}
# At this point, both the numerator and denominator are finite, non-zero
# numbers.
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my (@params, $scale);
($x, @params) = $x->_find_round_parameters($r[0], $r[1], $r[2], $y);
if ($x -> is_nan()) { # error in _find_round_parameters?
$x -> round(@r);
return $wantarray ? ($x, $class -> bnan(@r)) : $x;
}
# 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[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
}
# Temporarily disable downgrading
my $dng = Math::BigFloat -> downgrade();
Math::BigFloat -> downgrade(undef);
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!
# Are both operands the same object, i.e., like $x -> bdiv($x)? If so,
# flipping the sign of $y also flips the sign of $x.
my $xsign = $x -> {sign};
my $ysign = $y -> {sign};
$y -> {sign} =~ tr/+-/-+/; # Flip the sign of $y, and see ...
my $same = $xsign ne $x -> {sign}; # ... if that changed the sign of $x.
$y -> {sign} = $ysign; # Re-insert the original sign.
if ($same) { # $x -> bdiv($x)
$x -> bone();
} else {
# make copy of $x in case of list context for later remainder
# calculation
$rem = $x -> copy() if $wantarray;
$x->{sign} = $x->{sign} ne $y->{sign} ? '-' : '+';
# promote Math::BigInt and its 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); # scale up
$x->{_m} = $LIB->_div($x->{_m}, $y->{_m}); # divide
# correct exponent of $x
($x->{_e}, $x->{_es})
= $LIB -> _ssub($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
# correct for 10**scale
($x->{_e}, $x->{_es})
= $LIB -> _ssub($x->{_e}, $x->{_es}, $LIB->_new($scale), '+');
$x -> bnorm(); # remove trailing zeros in mantissa
}
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x->{accuracy} = undef; # clear before round
$x -> bround($params[0], $params[2]); # then round accordingly
} else {
$x->{precision} = undef; # 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
$x->{accuracy} = undef;
$x->{precision} = undef;
}
# Restore downgrading
Math::BigFloat -> downgrade($dng);
if ($wantarray) {
$x -> bint();
$rem -> btmod($y, @params); # copy already done
if ($fallback) {
# clear a/p after round, since user did not request it
$rem->{accuracy} = undef;
$rem->{precision} = undef;
}
$x -> _dng() if $x -> is_int();
$rem -> _dng() if $rem -> is_int();
return $x, $rem;
}
$x -> _dng() if $x -> is_int();
$x; # rounding already done above
}
sub btmod {
# (dividend: BFLOAT or num_str, divisor: BFLOAT or num_str) return
# remainder
# set up parameters
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('btmod');
# At least one argument is NaN. This is handled the same way as in
# Math::BigInt -> btmod().
return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
# Modulo zero. This is handled the same way as in Math::BigInt -> btmod().
if ($y -> is_zero()) {
return $x -> round(@r);
}
# Numerator (dividend) is +/-inf. This is handled the same way as in
# Math::BigInt -> btmod().
if ($x -> is_inf()) {
return $x -> bnan(@r);
}
# Denominator (divisor) is +/-inf. This is handled the same way as in
# Math::BigInt -> btmod().
if ($y -> is_inf()) {
return $x -> round(@r);
}
# Modulo is zero if $x is zero or if $x is an integer and $y is +/-1.
return $x -> bzero(@r) if $x -> is_zero()
|| ($x -> is_int() &&
# check that $y == +1 or $y == -1:
($LIB->_is_zero($y->{_e}) && $LIB->_is_one($y->{_m})));
# Numerator (dividend) and denominator (divisor) are identical. Return
# zero.
my $cmp = $x -> bacmp($y); # $x <=> $y
if ($cmp == 0) { # $x == $y => result 0
return $x -> bzero(@r);
}
# Compare the exponents of $x and $y.
my $ecmp = $LIB->_scmp($x->{_e}, $x->{_es}, $y->{_e}, $y->{_es});
if ($ecmp > 0) {
# $x has a larger exponent than $y, so shift the mantissa of $x by the
# difference between the exponents of $x and $y.
#
# 123e+2 % 456e+1 => 1230 % 456 (+2 - +1 = 1)
# 123e+2 % 456e-1 => 123000 % 456 (+2 - -1 = 3)
# 456e-1 % 123e-3 => 12300 % 456 (-1 - -3 = 2)
# get the difference between exponents; $ds is always "+" here
my ($de, $ds) = $LIB->_ssub($LIB->_copy($x->{_e}), $x->{_es},
$y->{_e}, $y->{_es});
# adjust the mantissa of x by the difference between exponents
$x->{_m} = $LIB->_lsft($x->{_m}, $de, 10);
# compute the modulus
$x->{_m} = $LIB->_mod($x->{_m}, $y->{_m});
# adjust the exponent of x to correct for the ajustment of the mantissa
($x->{_e}, $x->{_es}) = $LIB->_ssub($x->{_e}, $x->{_es}, $de, $ds);
} elsif ($ecmp < 0) {
# $x has a smaller exponent than $y, so shift the mantissa of $y by the
# difference between the exponents of $x and $y.
#
# 123456e+1 % 78e+2 => 123456 % 780 (+2 - +1 = 1)
# 123456e-2 % 78e+1 => 123456 % 78000 (+1 - -2 = 3)
# get the difference between exponents; $ds is always "+" here
my ($de, $ds) = $LIB->_ssub($LIB->_copy($y->{_e}), $y->{_es},
$x->{_e}, $x->{_es});
# adjust the mantissa of y by the difference between exponents
my $ym = $LIB->_lsft($LIB->_copy($y->{_m}), $de, 10);
# compute the modulus
$x->{_m} = $LIB->_mod($x->{_m}, $ym);
} else {
# $x has the same exponent as $y, so compute the modulus directly
# compute the modulus
$x->{_m} = $LIB->_mod($x->{_m}, $y->{_m});
}
$x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # fix sign for -0
$x -> bnorm();
$x -> round($r[0], $r[1], $r[2], $y);
$x -> _dng() if $x -> is_int();
return $x;
}
sub binv {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('binv');
# bone() might perform downgrading, so temporarily disable downgrading
my $dng = Math::BigFloat -> downgrade();
Math::BigFloat -> downgrade(undef);
my $inv = $class -> bone() -> bdiv($x, @r);
# Restore downgrading
Math::BigFloat -> downgrade($dng);
%$x = %$inv;
$x -> round(@r);
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
sub bsqrt {
# calculate square root
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bsqrt');
# Handle trivial cases.
return $x -> bnan(@r) if $x -> is_nan();
return $x -> binf("+", @r) if $x -> is_inf("+");
return $x -> round(@r) if $x -> is_zero() || $x -> is_one();
# We don't support complex numbers.
if ($x -> is_neg()) {
return $x -> _upg() -> bsqrt(@r) if $class -> upgrade();
return $x -> bnan(@r);
}
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my (@params, $scale);
($x, @params) = $x->_find_round_parameters(@r);
# error in _find_round_parameters?
return $x -> bnan(@r) if $x -> 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
$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
}
# Shift the significand left or right to get the desired number of digits,
# which is 2*$scale with possibly one extra digit to ensure that the
# exponent is an even number.
my $l = $LIB -> _len($x->{_m});
my $n = 2 * $scale - $l; # how much should we shift?
$n++ if ($l % 2 xor $LIB -> _is_odd($x->{_e}));
my ($na, $ns) = $n < 0 ? (abs($n), "-") : ($n, "+");
$na = $LIB -> _new($na);
$x->{_m} = $ns eq "+" ? $LIB -> _lsft($x->{_m}, $na, 10)
: $LIB -> _rsft($x->{_m}, $na, 10);
$x->{_m} = $LIB -> _sqrt($x->{_m});
# Adjust the exponent by the amount that we shifted the significand. The
# square root of the exponent is simply half of it: sqrt(10^(2*a)) = 10^a.
($x->{_e}, $x->{_es}) = $LIB -> _ssub($x->{_e}, $x->{_es}, $na, $ns);
$x->{_e} = $LIB -> _div($x->{_e}, $LIB -> _new("2"));
# Normalize to get rid of any trailing zeros in the significand.
$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
$x->{accuracy} = undef;
$x->{precision} = undef;
}
$x -> round(@r);
$x -> _dng() if $x -> is_int();
$x;
}
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, @_);
}
# Don't modify constant (read-only) objects.
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 $x -> _upg() -> bpow($y, $a, $p, $r) if $class -> 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();
# We should NOT be looking at private variables of other objects. Fixme XXX
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);
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
sub broot {
# calculate $y'th root of $x
# set up parameters
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('broot');
# Handle trivial cases.
return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
if ($x -> is_neg()) {
# -27 ** (1/3) = -(27 ** (1/3)) = -3
return $x -> broot($y -> copy() -> bneg(), @r) -> bneg()
if ($x -> is_int() && $y -> is_int() &&
$y -> is_neg() && $y -> is_odd());
return $x -> _upg -> broot($y, @r) if $class -> upgrade();
return $x -> bnan(@r);
}
# NaN handling: $x ** 1/0, x or y NaN, or y inf/-inf or y == 0
return $x -> bnan(@r) if ($x->{sign} !~ /^\+/ || $y -> is_zero() ||
$y->{sign} !~ /^\+$/);
# Trivial cases.
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(@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[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.
my $ab = $class -> accuracy();
my $pb = $class -> precision();
$class -> accuracy(undef);
$class -> precision(undef);
# Disabling upgrading and downgrading is no longer necessary to avoid an
# infinite recursion, but it avoids unnecessary upgrading and downgrading
# in the intermediate computations.
my $upg = $class -> upgrade();
my $dng = $class -> downgrade();
$class -> upgrade(undef);
$class -> downgrade(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.
$x->{accuracy} = undef;
$x->{precision} = undef;
# 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);
}
# Inverse: $x ** (-1) => 1 / $x
elsif ($y -> is_one('-')) {
$x -> binv($scale + 4);
}
# General case: calculate the broot() as integer result first, and if it
# fits, return it rightaway (but only if $x and $y are integer).
#
# This code should be improved. XXX
else {
# Temporarily disable upgrading in Math::BigInt.
my $mbi_upg = Math::BigInt -> upgrade();
Math::BigInt -> upgrade(undef);
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_int());
# if ($exact)
if ($int -> copy() -> bpow($y -> as_int()) == $x -> as_int()) {
# 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);
$u->{accuracy} = undef;
$u->{precision} = undef;
$x -> bpow($u, $scale+4); # el cheapo
}
Math::BigInt -> upgrade($mbi_upg);
}
$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
$x->{accuracy} = undef;
$x->{precision} = undef;
}
# Restore globals. We need to do it like this, because setting one
# undefines the other.
if (defined $ab) {
$class -> accuracy($ab);
} else {
$class -> precision($pb);
}
$class -> upgrade($upg);
$class -> downgrade($dng);
$x -> round(@r);
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
sub bmuladd {
# multiply two numbers and add the third to the result
# set up parameters
my ($class, $x, $y, $z, @r)
= ref($_[0]) && ref($_[0]) eq ref($_[1]) && ref($_[1]) eq ref($_[2])
? (ref($_[0]), @_)
: objectify(3, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bmuladd');
# At least one of x, y, and z is a NaN
return $x -> bnan(@r) if ($x -> is_nan() ||
$y -> is_nan() ||
$z -> is_nan());
# At least one of x, y, and z is an Inf
if ($x -> is_inf("-")) {
if ($y -> is_neg()) { # x = -inf, y < 0
if ($z -> is_inf("-")) {
return $x -> bnan(@r);
} else {
return $x -> binf("+", @r);
}
} elsif ($y -> is_zero()) { # x = -inf, y = 0
return $x -> bnan(@r);
} else { # x = -inf, y > 0
if ($z->{sign} eq "+inf") {
return $x -> bnan(@r);
} else {
return $x -> binf("-", @r);
}
}
} elsif ($x->{sign} eq "+inf") {
if ($y -> is_neg()) { # x = +inf, y < 0
if ($z->{sign} eq "+inf") {
return $x -> bnan(@r);
} else {
return $x -> binf("-", @r);
}
} elsif ($y -> is_zero()) { # x = +inf, y = 0
return $x -> bnan(@r);
} else { # x = +inf, y > 0
if ($z -> is_inf("-")) {
return $x -> bnan(@r);
} else {
return $x -> binf("+", @r);
}
}
} elsif ($x -> is_neg()) {
if ($y -> is_inf("-")) { # -inf < x < 0, y = -inf
if ($z -> is_inf("-")) {
return $x -> bnan(@r);
} else {
return $x -> binf("+", @r);
}
} elsif ($y->{sign} eq "+inf") { # -inf < x < 0, y = +inf
if ($z->{sign} eq "+inf") {
return $x -> bnan(@r);
} else {
return $x -> binf("-", @r);
}
} else { # -inf < x < 0, -inf < y < +inf
if ($z -> is_inf("-")) {
return $x -> binf("-", @r);
} elsif ($z->{sign} eq "+inf") {
return $x -> binf("+", @r);
}
}
} elsif ($x -> is_zero()) {
if ($y -> is_inf("-")) { # x = 0, y = -inf
return $x -> bnan(@r);
} elsif ($y->{sign} eq "+inf") { # x = 0, y = +inf
return $x -> bnan(@r);
} else { # x = 0, -inf < y < +inf
if ($z -> is_inf("-")) {
return $x -> binf("-", @r);
} elsif ($z->{sign} eq "+inf") {
return $x -> binf("+", @r);
}
}
} elsif ($x -> is_pos()) {
if ($y -> is_inf("-")) { # 0 < x < +inf, y = -inf
if ($z->{sign} eq "+inf") {
return $x -> bnan(@r);
} else {
return $x -> binf("-", @r);
}
} elsif ($y->{sign} eq "+inf") { # 0 < x < +inf, y = +inf
if ($z -> is_inf("-")) {
return $x -> bnan(@r);
} else {
return $x -> binf("+", @r);
}
} else { # 0 < x < +inf, -inf < y < +inf
if ($z -> is_inf("-")) {
return $x -> binf("-", @r);
} elsif ($z->{sign} eq "+inf") {
return $x -> binf("+", @r);
}
}
}
# At this point, we know that x, y, and z are finite numbers
# Rather than copying $y and/or $z, perhaps we should assign the output to
# a temporary $x value, and assign the final result to $x? XXX
$y = $y -> copy() if refaddr($y) eq refaddr($x);
$z = $z -> copy() if refaddr($z) eq refaddr($x);
# aEb * cEd = (a*c)E(b+d)
$x->{_m} = $LIB->_mul($x->{_m}, $y->{_m});
($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} ? '-' : '+';
# 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) = $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}) = $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}) =
$LIB -> _sadd($x->{_m}, $x->{sign}, $add, $z->{sign});
}
# delete trailing zeros, then round
$x -> bnorm() -> round(@r);
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
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, @r)
= ref($_[0]) && ref($_[0]) eq ref($_[1]) && ref($_[1]) eq ref($_[2])
? (ref($_[0]), @_)
: objectify(3, @_);
# Don't modify constant (read-only) objects.
return $num if $num -> modify('bmodpow');
return $num -> bnan(@r)
if $mod -> is_nan() || $exp -> is_nan() || $mod -> is_nan();
# check modulus for valid values
return $num -> bnan(@r) if $mod->{sign} ne '+' || $mod -> is_zero();
# check exponent for valid values
if ($exp->{sign} =~ /\w/) {
# i.e., if it's NaN, +inf, or -inf...
return $num -> bnan(@r);
}
$num -> bmodinv($mod, @r) if $exp->{sign} eq '-';
# check num for valid values (also NaN if there was no inverse but $exp < 0)
return $num -> bnan(@r) 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);
$num -> round(@r);
$num -> _dng() if ($num -> is_int() ||
$num -> is_inf() ||
$num -> is_nan());
return $num;
}
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, @r);
# Only objectify the base if it is defined, since an undefined base, as in
# $x->blog() or $x->blog(undef) signals that the base is Euler's number =
# 2.718281828...
if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
# E.g., Math::BigFloat->blog(256, 2)
($class, $x, $base, @r) =
defined $_[2] ? objectify(2, @_) : objectify(1, @_);
} else {
# E.g., $x->blog(2) or the deprecated Math::BigFloat::blog(256, 2)
($class, $x, $base, @r) =
defined $_[1] ? objectify(2, @_) : objectify(1, @_);
}
# Don't modify constant (read-only) objects.
return $x if $x -> modify('blog');
# Handle all exception cases and all trivial cases. I have used Wolfram
# Alpha (http://www.wolframalpha.com) as the reference for these cases.
return $x -> bnan(@r) if $x -> is_nan();
if (defined $base) {
$base = $class -> new($base)
unless defined(blessed($base)) && $base -> isa(__PACKAGE__);
if ($base -> is_nan() || $base -> is_one()) {
return $x -> bnan(@r);
} elsif ($base -> is_inf() || $base -> is_zero()) {
return $x -> bnan(@r) if $x -> is_inf() || $x -> is_zero();
return $x -> bzero(@r);
} elsif ($base -> is_negative()) { # -inf < base < 0
return $x -> bzero(@r) if $x -> is_one(); # x = 1
return $x -> bone('+', @r) if $x == $base; # x = base
# we can't handle these cases, so upgrade, if we can
return $x -> _upg() -> blog($base, @r) if $class -> upgrade();
return $x -> bnan(@r);
}
return $x -> bone(@r) if $x == $base; # 0 < base && 0 < x < inf
}
if ($x -> is_inf()) { # x = +/-inf
my $sign = defined($base) && $base < 1 ? '-' : '+';
return $x -> binf($sign, @r);
} elsif ($x -> is_neg()) { # -inf < x < 0
return $x -> _upg() -> blog($base, @r) if $class -> upgrade();
return $x -> bnan(@r);
} elsif ($x -> is_one()) { # x = 1
return $x -> bzero(@r);
} elsif ($x -> is_zero()) { # x = 0
my $sign = defined($base) && $base < 1 ? '+' : '-';
return $x -> binf($sign, @r);
}
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my ($scale, @params);
($x, @params) = $x->_find_round_parameters(@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[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.
my $ab = $class -> accuracy();
my $pb = $class -> precision();
$class -> accuracy(undef);
$class -> precision(undef);
# Disabling upgrading and downgrading is no longer necessary to avoid an
# infinite recursion, but it avoids unnecessary upgrading and downgrading
# in the intermediate computations.
my $upg = $class -> upgrade();
my $dng = $class -> downgrade();
$class -> upgrade(undef);
$class -> downgrade(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.
$x->{accuracy} = undef;
$x->{precision} = undef;
my $done = 0;
# If both $x and $base are integers, try to calculate an integer result
# first. This is very fast, and if the exact result was found, we are done.
if (defined($base) && $base -> is_int() && $x -> is_int()) {
my $x_lib = $LIB -> _new($x -> bdstr());
my $b_lib = $LIB -> _new($base -> bdstr());
($x_lib, my $exact) = $LIB -> _log_int($x_lib, $b_lib);
if ($exact) {
$x->{_m} = $x_lib;
$x->{_e} = $LIB -> _zero();
$x -> bnorm();
$done = 1;
}
}
# If the integer result was not accurate, compute the natural logarithm
# log($x) (using reduction by 10 and possibly also by 2), and if a
# different base was requested, convert the result with log($x)/log($base).
unless ($done) {
$x -> _log_10($scale);
if (defined $base) {
# 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
$x->{accuracy} = undef;
$x->{precision} = undef;
}
# Restore globals. We need to do it like this, because setting one
# undefines the other.
if (defined $ab) {
$class -> accuracy($ab);
} else {
$class -> precision($pb);
}
$class -> upgrade($upg);
$class -> downgrade($dng);
$x -> round(@r);
return $x -> _dng() if $x -> is_int();
return $x;
}
sub bexp {
# Calculate e ** X (Euler's number to the power of X)
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bexp');
return $x -> bnan(@r) if $x -> is_nan();
return $x -> binf(@r) if $x -> is_inf("+");
return $x -> bzero(@r) if $x -> is_inf("-");
# Get the rounding parameters, if any.
my $fallback = 0;
my ($scale, @params);
($x, @params) = $x -> _find_round_parameters(@r);
# Error in _find_round_parameters?
return $x -> bnan(@r) if $x -> is_nan();
return $x -> bone(@r) if $x -> is_zero();
# If no rounding parameters are give, use fallback.
if (!@params) {
$params[0] = $class -> div_scale(); # fallback accuracy
$params[1] = undef; # no precision
$params[2] = $r[2]; # rounding mode
$scale = $params[0];
$fallback = 1; # to clear a/p afterwards
} else {
if (defined($params[0])) {
$scale = $params[0];
} else {
# We perform the computations below using accuracy only, not
# precision, so when precision is given, we need to "convert" this
# to accuracy. To do that, we need to know, at least approximately,
# how many digits there will be in the final result.
#
# log10(exp($x)) = log(exp($x)) / log(10) = $x / log(10)
#$scale = 1 + int(log($ms) / log(10) + $es) - $params[1];
my $ndig = $x -> numify() / log(10);
$scale = 1 + int($ndig) - $params[1];
}
}
# Add extra digits to reduce the consequence of round-off errors in the
# intermediate computations.
$scale += 4;
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.
my $ab = $class -> accuracy();
my $pb = $class -> precision();
$class -> accuracy(undef);
$class -> precision(undef);
# Disabling upgrading and downgrading is no longer necessary to avoid an
# infinite recursion, but it avoids unnecessary upgrading and downgrading
# in the intermediate computations.
my $upg = $class -> upgrade();
my $dng = $class -> downgrade();
$class -> upgrade(undef);
$class -> downgrade(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.
$x->{accuracy} = undef;
$x->{precision} = undef;
my $x_orig = $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 number of steps needed to get $A and $B sufficiently large.
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);
}
# Now $x contains now an estimate of e, with some additional digits.
if ($x_orig -> is_one()) {
# else just round the already computed result
$x->{accuracy} = undef;
$x->{precision} = undef;
# 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
}
} else {
# Use the fact exp(x) = exp(x/n)**n. In our case, n = 2**i for some
# integer i. We use this to compute exp(y) where y = x / (2**i) and
# 1 <= |y| < 2.
#
# The code below is similar to the code found in to_ieee754().
# 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_orig -> nparts();
my $ms = $m -> numify();
my $es = $e -> numify();
# 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.
my $mant = $x_orig -> copy() -> babs();
my $expo;
my $one = $class -> bone();
my $two = $class -> new("2");
my $half = $class -> new("0.5");
my $expo_est = (log(abs($ms))/log(10) + $es) * log(10)/log(2);
$expo_est = int($expo_est);
# 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($half -> copy() -> bpow($expo));
} elsif ($expo_est < 0) {
my $expo_abs = $expo -> copy() -> bneg();
$mant -> bmul($two -> copy() -> bpow($expo_abs));
}
# Final adjustment of the estimate above.
while ($mant -> bcmp($two) >= 0) { # $mant <= $two
$mant -> bmul($half);
$expo -> binc();
}
while ($mant -> bcmp($one) < 0) { # $mant > $one
$mant -> bmul($two);
$expo -> bdec();
}
# Because of the upscaling, we need some additional digits.
my $rescale = int($scale + abs($expo) * log(2) / log(10) + 1);
$rescale = 4 if $rescale < 4;
$x -> bpow($mant, $rescale);
my $pow2 = $two -> bpow($expo, $rescale);
$pow2 -> bneg() if $x_orig -> is_negative();
# The bpow() below fails with the GMP and GMPz libraries if abs($pow2)
# >= 2**30 = 1073741824. With the Pari library, it fails already when
# abs($pow) >= 2**13 = 8192. With the Calc library, it is rediculously
# slow when abs($pow2) is large. Fixme?
croak "cannot compute bexp(); input value is too large"
if $pow2 -> copy() -> babs() -> bcmp("1073741824") >= 0;
$x -> bpow($pow2, $rescale);
# Rounding parameters given as arguments currently don't override
# instance variables, so accuracy (which is set in the computations
# above) must be undefined before rounding. Fixme.
$x->{accuracy} = undef;
$x -> round(@params);
}
if ($fallback) {
# clear a/p after round, since user did not request it
$x->{accuracy} = undef;
$x->{precision} = undef;
}
# Restore globals. We need to do it like this, because setting one
# undefines the other.
if (defined $ab) {
$class -> accuracy($ab);
} else {
$class -> precision($pb);
}
$class -> upgrade($upg);
$class -> downgrade($dng);
# If downgrading, remember to preserve the relevant instance parameters.
# There should be a more elegant way to do this. Fixme.
$x -> round(@r);
$x -> _dng() if $x -> is_int();
$x;
}
sub bilog2 {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bilog2');
return $x -> bnan(@r) if $x -> is_nan();
return $x -> binf("+", @r) if $x -> is_inf("+");
return $x -> binf("-", @r) if $x -> is_zero();
if ($x -> is_neg()) {
return $x -> _upg() -> bilog2(@r) if $class -> upgrade();
return $x -> bnan(@r);
}
if ($x->{_es} eq '-') { # exponent < 0
$x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
} elsif (! $LIB->_is_zero($x->{_e})) { # exponent > 0
$x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10);
}
$x->{_m} = $LIB -> _ilog2($x->{_m});
$x->{_e} = $LIB -> _zero();
$x -> bnorm() -> round(@r);
$x -> _dng();
return $x;
}
sub bilog10 {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bilog10');
return $x -> bnan(@r) if $x -> is_nan();
return $x -> binf("+", @r) if $x -> is_inf("+");
return $x -> binf("-", @r) if $x -> is_zero();
if ($x -> is_neg()) {
return $x -> _upg() -> bilog10(@r) if $class -> upgrade();
return $x -> bnan(@r);
}
if ($x->{_es} eq '-') { # exponent < 0
$x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
} elsif (! $LIB->_is_zero($x->{_e})) { # exponent > 0
$x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10);
}
$x->{_m} = $LIB -> _ilog10($x->{_m});
$x->{_e} = $LIB -> _zero();
$x -> bnorm() -> round(@r);
$x -> _dng();
return $x;
}
sub bclog2 {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bclog2');
return $x -> bnan(@r) if $x -> is_nan();
return $x -> binf("+", @r) if $x -> is_inf("+");
return $x -> binf("-", @r) if $x -> is_zero();
if ($x -> is_neg()) {
return $x -> _upg() -> bclog2(@r) if $class -> upgrade();
return $x -> bnan(@r);
}
if ($x->{_es} eq '-') { # exponent < 0
$x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
} elsif (! $LIB->_is_zero($x->{_e})) { # exponent > 0
$x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10);
}
$x->{_m} = $LIB -> _clog2($x->{_m});
$x->{_e} = $LIB -> _zero();
$x -> bnorm() -> round(@r);
$x -> _dng();
return $x;
}
sub bclog10 {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bclog10');
return $x -> bnan(@r) if $x -> is_nan();
return $x -> binf("+", @r) if $x -> is_inf("+");
return $x -> binf("-", @r) if $x -> is_zero();
if ($x -> is_neg()) {
return $x -> _upg() -> bclog10(@r) if $class -> upgrade();
return $x -> bnan(@r);
}
if ($x->{_es} eq '-') { # exponent < 0
$x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
} elsif (! $LIB->_is_zero($x->{_e})) { # exponent > 0
$x->{_m} = $LIB->_lsft($x->{_m}, $x->{_e}, 10);
}
$x->{_m} = $LIB -> _clog10($x->{_m});
$x->{_e} = $LIB -> _zero();
$x -> bnorm() -> round(@r);
$x -> _dng();
return $x;
}
sub bnok {
# Calculate n over k (binomial coefficient or "choose" function) as
# integer. set up parameters
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Don't modify constant (read-only) objects.
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()));
# This should be implemented without converting to Math::BigInt. XXX
my $xint = $x -> as_int(); # to Math::BigInt
my $yint = $y -> as_int(); # to Math::BigInt
$xint -> bnok($yint);
$xint -> round(@r);
my $xflt = $xint -> as_float();
$x -> {sign} = $xflt -> {sign};
$x -> {_m} = $xflt -> {_m};
$x -> {_es} = $xflt -> {_es};
$x -> {_e} = $xflt -> {_e};
return $x -> _dng();
return $x;
}
sub bperm {
# Calculate n over k (binomial coefficient or "choose" function) as
# integer. set up parameters
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bperm');
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()));
# This should be implemented without converting to Math::BigInt. XXX
my $xint = $x -> as_int(); # to Math::BigInt
my $yint = $y -> as_int(); # to Math::BigInt
$xint -> bperm($yint);
$xint -> round(@r);
my $xflt = $xint -> as_float();
$x -> {sign} = $xflt -> {sign};
$x -> {_m} = $xflt -> {_m};
$x -> {_es} = $xflt -> {_es};
$x -> {_e} = $xflt -> {_e};
return $x -> _dng();
return $x;
}
sub bsin {
# Calculate a sinus of x.
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# First we apply range reduction to x. This is because if x is large, the
# Taylor series converges slowly and requires higher accuracy in the
# intermediate computation. The Taylor series is:
#
# x^3 x^5 x^7 x^9
# sin(x) = x - --- + --- - --- + --- ...
# 3! 5! 7! 9!
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bsin');
return $x -> bzero(@r) if $x -> is_zero();
return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf();
# Get the rounding parameters, if any.
my $fallback = 0;
my ($scale, @params);
($x, @params) = $x -> _find_round_parameters(@r);
# Error in _find_round_parameters?
return $x -> bnan(@r) if $x -> is_nan();
# If no rounding parameters are given, use fallback.
if (!@params) {
$params[0] = $class -> div_scale(); # fallback accuracy
$params[1] = undef; # no precision
$params[2] = $r[2]; # rounding mode
$scale = $params[0];
$fallback = 1; # to clear a/p afterwards
} else {
if (defined($params[0])) {
$scale = $params[0];
} else {
# We perform the computations below using accuracy only, not
# precision, so when precision is given, we need to "convert" this
# to accuracy.
$scale = 1 - $params[1];
}
}
# Add more digits to the scale if the magnitude of $x is large.
my ($m, $e) = $x -> nparts();
$scale += $e if $x >= 10;
$scale = 4 if $scale < 4;
# When user set globals, they would interfere with our calculation, so
# disable them and later re-enable them
my $ab = $class -> accuracy();
my $pb = $class -> precision();
$class -> accuracy(undef);
$class -> precision(undef);
# Disabling upgrading and downgrading is no longer necessary to avoid an
# infinite recursion, but it avoids unnecessary upgrading and downgrading
# in the intermediate computations.
my $upg = $class -> upgrade();
my $dng = $class -> downgrade();
$class -> upgrade(undef);
$class -> downgrade(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.
$x->{accuracy} = undef;
$x->{precision} = undef;
my $sin_prev; # the previous approximation of sin(x)
my $sin; # the current approximation of sin(x)
while (1) {
# Compute constants to the current scale.
my $pi = $class -> bpi($scale); # 𝜋
my $twopi = $pi -> copy() -> bmul("2"); # 2𝜋
my $halfpi = $pi -> copy() -> bmul("0.5"); # 𝜋/2
# Use the fact that sin(-x) = -sin(x) to reduce the range to the
# interval to [0,∞).
my $xsgn = $x < 0 ? -1 : 1;
my $x = $x -> copy() -> babs();
# Use the fact that sin(2𝜋x) = sin(x) to reduce the range to the
# interval to [0, 2𝜋).
$x -> bmod($twopi, $scale);
# Use the fact that sin(x+𝜋) = -sin(x) to reduce the range to the
# interval to [0,𝜋).
if ($x -> bcmp($pi) > 0) {
$xsgn = -$xsgn;
$x -> bsub($pi);
}
# Use the fact that sin(𝜋-x) = sin(x) to reduce the range to the
# interval [0,𝜋/2).
if ($x -> bcmp($halfpi) > 0) {
$x -> bsub($pi) -> bneg(); # 𝜋 - x
}
my $tol = $class -> new("1E-". ($scale-1));
my $xsq = $x -> copy() -> bmul($x, $scale) -> bneg();
my $term = $x -> copy();
my $fac = $class -> bone();
my $n = $class -> bone();
$sin = $x -> copy(); # initialize sin(x) to the first term
while (1) {
$n -> binc();
$fac = $n -> copy();
$n -> binc();
$fac -> bmul($n);
$term -> bmul($xsq, $scale) -> bdiv($fac, $scale);
$sin -> badd($term, $scale);
last if $term -> copy() -> babs() -> bcmp($tol) < 0;
}
$sin -> bneg() if $xsgn < 0;
# Rounding parameters given as arguments currently don't override
# instance variables, so accuracy (which is set in the computations
# above) must be undefined before rounding. Fixme.
$sin->{accuracy} = undef;
$sin -> round(@params);
# Compare the current approximation of sin(x) with the previous one,
# and if they are identical, we're done.
if (defined $sin_prev) {
last if $sin -> bcmp($sin_prev) == 0;
}
# If the current approximation of sin(x) is different from the previous
# approximation, double the scale (accuracy) and retry.
$sin_prev = $sin;
$scale *= 2;
}
# Assign the result to the invocand.
%$x = %$sin;
if ($fallback) {
# clear a/p after round, since user did not request it
$x->{accuracy} = undef;
$x->{precision} = undef;
}
# Restore globals. We need to do it like this, because setting one
# undefines the other.
if (defined $ab) {
$class -> accuracy($ab);
} else {
$class -> precision($pb);
}
$class -> upgrade($upg);
$class -> downgrade($dng);
# rounding has already been done
$x -> _dng() if $x -> is_int();
$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!
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bcos');
# we need to limit the accuracy to protect against overflow
my $fallback = 0;
my ($scale, @params);
($x, @params) = $x->_find_round_parameters(@r);
# error in _find_round_parameters?
return $x if $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.
my $ab = $class -> accuracy();
my $pb = $class -> precision();
$class -> accuracy(undef);
$class -> precision(undef);
# Disabling upgrading and downgrading is no longer necessary to avoid an
# infinite recursion, but it avoids unnecessary upgrading and downgrading
# in the intermediate computations.
my $upg = $class -> upgrade();
my $dng = $class -> downgrade();
$class -> upgrade(undef);
$class -> downgrade(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.
$x->{accuracy} = undef;
$x->{precision} = 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();
$x->{accuracy} = undef;
$x->{precision} = undef;
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); # n*(n+1)
$factorial -> binc();
$below -> bmul($factorial); # n*(n+1)
$factorial -> binc();
}
# 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
$x->{accuracy} = undef;
$x->{precision} = undef;
}
# Restore globals. We need to do it like this, because setting one
# undefines the other.
if (defined $ab) {
$class -> accuracy($ab);
} else {
$class -> precision($pb);
}
$class -> upgrade($upg);
$class -> downgrade($dng);
$x -> round(@r);
$x -> _dng() if $x -> is_int();
$x;
}
sub batan {
# Calculate a arcus tangens of x.
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# taylor: x^3 x^5 x^7 x^9
# atan = x - --- + --- - --- + --- ...
# 3 5 7 9
# Don't modify constant (read-only) objects.
return $x if $x -> modify('batan');
return $x -> bnan(@r) 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(@r);
# Error in _find_round_parameters?
return $x -> bnan(@r) if $x -> is_nan();
if ($x->{sign} =~ /^[+-]inf\z/) {
# +inf result is PI/2
# -inf result is -PI/2
# calculate PI/2
my $pi = $class -> bpi(@r);
# modify $x in place
$x->{_m} = $pi->{_m};
$x->{_e} = $pi->{_e};
$x->{_es} = $pi->{_es};
# -y => -PI/2, +y => PI/2
$x->{sign} = substr($x->{sign}, 0, 1); # "+inf" => "+"
$x -> {_m} = $LIB->_div($x->{_m}, $LIB->_new(2));
return $x;
}
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
}
# 1 or -1 => PI/4
# inlined is_one() && is_one('-')
if ($LIB->_is_one($x->{_m}) && $LIB->_is_zero($x->{_e})) {
my $pi = $class -> bpi($scale - 3);
# modify $x in place
$x->{_m} = $pi->{_m};
$x->{_e} = $pi->{_e};
$x->{_es} = $pi->{_es};
# leave the sign of $x alone (+1 => +PI/4, -1 => -PI/4)
$x->{_m} = $LIB->_div($x->{_m}, $LIB->_new(4));
return $x;
}
# When user set globals, they would interfere with our calculation, so
# disable them and later re-enable them.
my $ab = $class -> accuracy();
my $pb = $class -> precision();
$class -> accuracy(undef);
$class -> precision(undef);
# Disable upgrading and downgrading.
my $upg = $class -> upgrade();
my $dng = $class -> downgrade();
$class -> upgrade(undef);
$class -> downgrade(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.
$x->{accuracy} = undef;
$x->{precision} = undef;
# 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 ($x -> bacmp($x -> copy() -> bone) >= 0) {
# calculate PI/2
$pi = $class -> bpi($scale - 3);
$pi->{_m} = $LIB->_div($pi->{_m}, $LIB->_new(2));
# calculate 1/$x:
my $x_copy = $x -> copy();
# modify $x in place
$x -> bone();
$x -> bdiv($x_copy, $scale);
}
my $fmul = 1;
foreach (0 .. int($scale / 20)) {
$fmul *= 2;
$x -> bdiv($x -> copy() -> bmul($x) -> binc() -> bsqrt($scale + 4) -> binc(),
$scale + 4);
}
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(3);
my $two = $class -> new(2);
$x->{accuracy} = undef;
$x->{precision} = undef;
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) {
$x -> badd($next);
} else {
$x -> bsub($next);
}
$sign = 1 - $sign; # alternatex
# calculate things for the next term
$over -> bmul($x2); # $x*$x
$below -> badd($two); # n += 2
}
$x -> bmul($fmul);
if (defined $pi) {
my $x_copy = $x -> copy();
# modify $x in place
$x->{_m} = $pi->{_m};
$x->{_e} = $pi->{_e};
$x->{_es} = $pi->{_es};
# PI/2 - $x
$x -> bsub($x_copy);
}
# 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.
$x->{accuracy} = undef;
$x->{precision} = undef;
}
# Restore globals. We need to do it like this, because setting one
# undefines the other.
if (defined $ab) {
$class -> accuracy($ab);
} else {
$class -> precision($pb);
}
$class -> upgrade($upg);
$class -> downgrade($dng);
return $x -> _dng() if ($x -> is_int() ||
$x -> is_inf());
$x;
}
sub batan2 {
# $y -> batan2($x) returns the arcus tangens of $y / $x.
# Set up parameters.
my ($class, $y, $x, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return $y if $y -> modify('batan2');
# Handle all NaN cases.
return $y -> bnan() if $x -> is_nan() || $y -> is_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) {
$y->{accuracy} = undef;
$y->{precision} = undef;
}
return $y;
}
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]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bfac');
return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-");
return $x -> binf("+", @r) if $x -> is_inf("+");
return $x -> bnan(@r) if $x -> is_neg() || !$x -> is_int();
return $x -> bone(@r) if $x -> is_zero() || $x -> is_one();
if ($x -> is_neg() || !$x -> is_int()) {
return $x -> _upg() -> bfac(@r) if $class -> upgrade();
return $x -> bnan(@r);
}
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(); # norm again
$x -> round(@r);
$x -> _dng();
return $x;
}
sub bdfac {
# compute double factorial, modify $x in place
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bdfac');
return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-");
return $x -> binf("+", @r) if $x -> is_inf("+");
return $x -> bnan(@r) if $x <= -2 || !$x -> is_int();
return $x -> bone(@r) 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(); # norm again
$x -> round(@r);
$x -> _dng();
return $x;
}
sub btfac {
# compute triple factorial
# set up parameters
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('btfac');
return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-");
return $x -> binf("+", @r) if $x -> is_inf("+");
if ($x <= -3 || !$x -> is_int()) {
return $x -> _upg() -> btfac(@r) if $class -> upgrade();
return $x -> bnan(@r);
}
my $k = $class -> new("3");
return $x -> bnan(@r) if $x <= -$k;
my $one = $class -> bone();
return $x -> bone(@r) if $x <= $one;
my $f = $x -> copy();
while ($f -> bsub($k) > $one) {
$x = $x -> bmul($f);
}
$x -> round(@r);
$x -> _dng();
return $x;
}
sub bmfac {
my ($class, $x, $k, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bmfac');
return $x -> bnan(@r) if $x -> is_nan() || $x -> is_inf("-") ||
!$k -> is_pos();
return $x -> binf("+", @r) if $x -> is_inf("+");
return $x -> bround(@r) if $k -> is_inf("+");
return $x -> bnan(@r) if !$x -> is_int() || !$k -> is_int();
return $x -> bnan(@r) if $k < 1 || $x <= -$k;
my $one = $class -> bone();
return $x -> bone(@r) if $x <= $one;
my $f = $x -> copy();
while ($f -> bsub($k) > $one) {
$x -> bmul($f);
}
$x -> round(@r);
$x -> _dng();
return $x;
}
sub bfib {
# compute Fibonacci number(s)
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
croak("bfib() requires a newer version of the $LIB library.")
unless $LIB -> can('_fib');
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bfib');
# List context.
if (wantarray) {
croak("bfib() can't return an infinitely long list of numbers")
if $x -> is_inf();
return if $x -> is_nan() || !$x -> is_int();
# The following places a limit on how large $x can be. Should this
# limit be removed? XXX
my $n = $x -> numify();
my @y;
{
$y[0] = $x -> copy() -> babs();
$y[0]{_m} = $LIB -> _zero();
$y[0]{_e} = $LIB -> _zero();
last if $n == 0;
$y[1] = $y[0] -> copy();
$y[1]{_m} = $LIB -> _one();
$y[1]{_e} = $LIB -> _zero();
last if $n == 1;
for (my $i = 2 ; $i <= abs($n) ; $i++) {
$y[$i] = $y[$i - 1] -> copy();
$y[$i]{_m} = $LIB -> _add($LIB -> _copy($y[$i - 1]{_m}),
$y[$i - 2]{_m});
}
# If negative, insert sign as appropriate.
if ($x -> is_neg()) {
for (my $i = 2 ; $i <= $#y ; $i += 2) {
$y[$i]{sign} = '-';
}
}
# The last element in the array is the invocand.
$x->{sign} = $y[-1]{sign};
$x->{_m} = $y[-1]{_m};
$x->{_es} = $y[-1]{_es};
$x->{_e} = $y[-1]{_e};
$y[-1] = $x;
}
for (@y) {
$_ -> bnorm();
$_ -> round(@r);
}
return @y;
}
# Scalar context.
else {
return $x if $x -> is_inf('+');
return $x -> bnan() if $x -> is_nan() || $x -> is_inf('-');
if ($x -> is_int()) {
$x->{sign} = $x -> is_neg() && $x -> is_even() ? '-' : '+';
$x->{_m} = $LIB -> _lsft($x->{_m}, $x -> {_e}, 10);
$x->{_e} = $LIB -> _zero();
$x->{_m} = $LIB -> _fib($x->{_m});
$x -> bnorm();
}
return $x -> round(@r);
}
}
sub blucas {
# compute Lucas number(s)
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
croak("blucas() requires a newer version of the $LIB library.")
unless $LIB -> can('_lucas');
# Don't modify constant (read-only) objects.
return $x if $x -> modify('blucas');
# List context.
if (wantarray) {
croak("blucas() can't return an infinitely long list of numbers")
if $x -> is_inf();
return if $x -> is_nan() || !$x -> is_int();
# The following places a limit on how large $x can be. Should this
# limit be removed? XXX
my $n = $x -> numify();
my @y;
{
$y[0] = $x -> copy() -> babs();
$y[0]{_m} = $LIB -> _two();
$y[0]{_e} = $LIB -> _zero();
last if $n == 0;
$y[1] = $y[0] -> copy();
$y[1]{_m} = $LIB -> _one();
$y[1]{_e} = $LIB -> _zero();
last if $n == 1;
for (my $i = 2 ; $i <= abs($n) ; $i++) {
$y[$i] = $y[$i - 1] -> copy();
$y[$i]{_m} = $LIB -> _add($LIB -> _copy($y[$i - 1]{_m}),
$y[$i - 2]{_m});
}
# If negative, insert sign as appropriate.
if ($x -> is_neg()) {
for (my $i = 2 ; $i <= $#y ; $i += 2) {
$y[$i]{sign} = '-';
}
}
# The last element in the array is the invocand.
$x->{sign} = $y[-1]{sign};
$x->{_m} = $y[-1]{_m};
$x->{_es} = $y[-1]{_es};
$x->{_e} = $y[-1]{_e};
$y[-1] = $x;
}
for (@y) {
$_ -> bnorm();
$_ -> round(@r);
}
return @y;
}
# Scalar context.
else {
return $x if $x -> is_inf('+');
return $x -> bnan() if $x -> is_nan() || $x -> is_inf('-');
if ($x -> is_int()) {
$x->{sign} = $x -> is_neg() && $x -> is_even() ? '-' : '+';
$x->{_m} = $LIB -> _lsft($x->{_m}, $x -> {_e}, 10);
$x->{_e} = $LIB -> _zero();
$x->{_m} = $LIB -> _lucas($x->{_m});
$x -> bnorm();
}
return $x -> round(@r);
}
}
sub blsft {
# shift left by $y in base $b, i.e., multiply by $b ** $y
# set up parameters
my ($class, $x, $y, $b, @r)
= ref($_[0]) && ref($_[0]) eq ref($_[1]) && ref($_[1]) eq ref($_[2])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('blsft');
return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
$b = 2 if !defined $b;
$b = $class -> new($b)
unless defined(blessed($b)) && $b -> isa(__PACKAGE__);
return $x -> bnan(@r) if $b -> is_nan();
# There needs to be more checking for special cases here. Fixme!
# shift by a negative amount?
return $x -> brsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
$x = $x -> bmul($b -> bpow($y), $r[0], $r[1], $r[2], $y);
$x -> round(@r);
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
sub brsft {
# shift right by $y in base $b, i.e., divide by $b ** $y
# set up parameters
my ($class, $x, $y, $b, @r)
= ref($_[0]) && ref($_[0]) eq ref($_[1]) && ref($_[1]) eq ref($_[2])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('brsft');
return $x -> bnan(@r) if $x -> is_nan() || $y -> is_nan();
# There needs to be more checking for special cases here. Fixme!
$b = 2 if !defined $b;
$b = $class -> new($b)
unless defined(blessed($b)) && $b -> isa(__PACKAGE__);
return $x -> bnan(@r) if $b -> is_nan();
# shift by a negative amount?
return $x -> blsft($y -> copy() -> babs(), $b) if $y -> {sign} =~ /^-/;
# call bdiv()
$x = $x -> bdiv($b -> bpow($y), $r[0], $r[1], $r[2], $y);
$x -> round(@r);
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
###############################################################################
# Bitwise methods
###############################################################################
# Bitwise left shift.
sub bblsft {
# We don't call objectify(), because the bitwise methods should not
# upgrade, even when upgrading is enabled.
my ($class, $x, $y, @r) = ref($_[0]) ? (ref($_[0]), @_) : @_;
# Don't modify constant (read-only) objects.
return $x if ref($x) && $x -> modify('bblsft');
# Let Math::BigInt do the job.
my $xint = Math::BigInt -> bblsft($x, $y, @r);
# Temporarily disable downgrading.
my $dng = $class -> downgrade();
$class -> downgrade(undef);
# convert to our class without downgrading.
my $xflt = $class -> new($xint);
# Reset downgrading.
$class -> downgrade($dng);
# If we are called as a class method, the first operand might not be an
# object of this class, so check.
if (defined(blessed($x)) && $x -> isa(__PACKAGE__)) {
$x -> {sign} = $xflt -> {sign};
$x -> {_m} = $xflt -> {_m};
$x -> {_es} = $xflt -> {_es};
$x -> {_e} = $xflt -> {_e};
} else {
$x = $xflt;
}
# Now we might downgrade.
$x -> round(@r);
$x -> _dng();
return $x;
}
# Bitwise right shift.
sub bbrsft {
# We don't call objectify(), because the bitwise methods should not
# upgrade, even when upgrading is enabled.
my ($class, $x, $y, @r) = ref($_[0]) ? (ref($_[0]), @_) : @_;
# Don't modify constant (read-only) objects.
return $x if ref($x) && $x -> modify('bbrsft');
# Let Math::BigInt do the job.
my $xint = Math::BigInt -> bbrsft($x, $y, @r);
# Temporarily disable downgrading.
my $dng = $class -> downgrade();
$class -> downgrade(undef);
# Convert to our class without downgrading.
my $xflt = $class -> new($xint);
# Reset downgrading.
$class -> downgrade($dng);
# If we are called as a class method, the first operand might not be an
# object of this class, so check.
if (defined(blessed($x)) && $x -> isa(__PACKAGE__)) {
$x -> {sign} = $xflt -> {sign};
$x -> {_m} = $xflt -> {_m};
$x -> {_es} = $xflt -> {_es};
$x -> {_e} = $xflt -> {_e};
} else {
$x = $xflt;
}
# Now we might downgrade.
$x -> round(@r);
$x -> _dng();
return $x;
}
sub band {
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return if $x -> modify('band');
# If $x and/or $y is Inf or NaN, return NaN.
return $x -> bnan(@r) if ($x -> is_nan() || $x -> is_inf() ||
$y -> is_nan() || $y -> is_inf());
# This should be implemented without converting to Math::BigInt. XXX
my $xint = $x -> as_int(); # to Math::BigInt
my $yint = $y -> as_int(); # to Math::BigInt
$xint -> band($yint);
$xint -> round(@r);
my $xflt = $xint -> as_float();
$x -> {sign} = $xflt -> {sign};
$x -> {_m} = $xflt -> {_m};
$x -> {_es} = $xflt -> {_es};
$x -> {_e} = $xflt -> {_e};
return $x -> _dng();
return $x;
}
sub bior {
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return if $x -> modify('bior');
# If $x and/or $y is Inf or NaN, return NaN.
return $x -> bnan(@r) if ($x -> is_nan() || $x -> is_inf() ||
$y -> is_nan() || $y -> is_inf());
# This should be implemented without converting to Math::BigInt. XXX
my $xint = $x -> as_int(); # to Math::BigInt
my $yint = $y -> as_int(); # to Math::BigInt
$xint -> bior($yint);
$xint -> round(@r);
my $xflt = $xint -> as_float();
$x -> {sign} = $xflt -> {sign};
$x -> {_m} = $xflt -> {_m};
$x -> {_es} = $xflt -> {_es};
$x -> {_e} = $xflt -> {_e};
return $x -> _dng();
return $x;
}
sub bxor {
my ($class, $x, $y, @r) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
# Don't modify constant (read-only) objects.
return if $x -> modify('bxor');
# If $x and/or $y is Inf or NaN, return NaN.
return $x -> bnan(@r) if ($x -> is_nan() || $x -> is_inf() ||
$y -> is_nan() || $y -> is_inf());
# This should be implemented without converting to Math::BigInt. XXX
my $xint = $x -> as_int(); # to Math::BigInt
my $yint = $y -> as_int(); # to Math::BigInt
$xint -> bxor($yint);
$xint -> round(@r);
my $xflt = $xint -> as_float();
$x -> {sign} = $xflt -> {sign};
$x -> {_m} = $xflt -> {_m};
$x -> {_es} = $xflt -> {_es};
$x -> {_e} = $xflt -> {_e};
return $x -> _dng();
return $x;
}
sub bnot {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return if $x -> modify('bnot');
return $x -> bnan(@r) if $x -> is_nan();
# This should be implemented without converting to Math::BigInt. XXX
my $xint = $x -> as_int(); # to Math::BigInt
$xint -> bnot();
$xint -> round(@r);
my $xflt = $xint -> as_float();
$x -> {sign} = $xflt -> {sign};
$x -> {_m} = $xflt -> {_m};
$x -> {_es} = $xflt -> {_es};
$x -> {_e} = $xflt -> {_e};
return $x -> _dng();
return $x;
}
###############################################################################
# Rounding methods
###############################################################################
sub bround {
# accuracy: preserve $N digits, and overwrite the rest with 0's
my ($class, $x, @a) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
if (($a[0] || 0) < 0) {
croak('bround() needs positive accuracy');
}
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bround');
my ($scale, $mode) = $x->_scale_a(@a);
if (!defined $scale) { # no-op
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
# Scale is now either $x->{accuracy}, $accuracy, or the input argument.
# 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
if (defined $x->{accuracy} && $x->{accuracy} < $scale) {
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
# scale < 0 makes no sense
# scale == 0 => keep all digits
# never round a +-inf, NaN
if ($scale <= 0 || $x->{sign} !~ /^[+-]$/) {
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
# 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->{accuracy} = $scale if !defined $x->{accuracy} || $x->{accuracy} > $scale;
$x -> _dng() if $x -> is_int();
return $x;
}
# pass sign to bround for '+inf' and '-inf' rounding modes
my $m = bless { sign => $x->{sign}, value => $x->{_m} }, 'Math::BigInt';
$m = $m -> bround($scale, $mode); # round mantissa
$x->{_m} = $m->{value}; # get our mantissa back
$x->{accuracy} = $scale; # remember rounding
$x->{precision} = undef; # and clear P
# bnorm() downgrades if necessary, so no need to check whether to
# downgrade.
$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 ($class, $x, @p) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bfround'); # no-op
my ($scale, $mode) = $x->_scale_p(@p);
if (!defined $scale) {
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
# never round a 0, +-inf, NaN
if ($x -> is_zero()) {
$x->{precision} = $scale if !defined $x->{precision} || $x->{precision} < $scale; # -3 < -2
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
if ($x->{sign} !~ /^[+-]$/) {
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
# don't round if x already has lower precision
if (defined $x->{precision} && $x->{precision} < 0 && $scale < $x->{precision}) {
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
$x->{precision} = $scale; # remember round in any case
$x->{accuracy} = undef; # and clear A
if ($scale < 0) {
# round right from the '.'
if ($x->{_es} eq '+') { # e >= 0 => nothing to round
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
$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
if ($scale > $dad) { # 0.123, scale >= 3 => exit
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
# 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)
if ($scale < $zad) {
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x -> bzero();
}
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
if ($scale == 1 && $dbt <= $dbd) {
$x -> _dng() if ($x -> is_int() ||
$x -> is_inf() ||
$x -> is_nan());
return $x;
}
# 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 = $m -> bround($scale, $mode);
$x->{_m} = $m->{value}; # get our mantissa back
# bnorm() downgrades if necessary, so no need to check whether to
# downgrade.
$x -> bnorm();
}
sub bfloor {
# round towards minus infinity
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bfloor');
return $x -> bnan(@r) if $x -> is_nan();
if ($x -> is_finite()) {
# if $x has digits after dot, remove them
if ($x->{_es} eq '-') {
$x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
$x->{_e} = $LIB->_zero();
$x->{_es} = '+';
# increment if negative
$x->{_m} = $LIB->_inc($x->{_m}) if $x->{sign} eq '-';
}
}
$x -> round(@r);
$x -> _dng();
return $x;
}
sub bceil {
# round towards plus infinity
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bceil');
return $x -> bnan(@r) if $x -> is_nan();
if ($x -> is_finite()) {
# if $x has digits after dot, remove them
if ($x->{_es} eq '-') {
$x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10);
$x->{_e} = $LIB->_zero();
$x->{_es} = '+';
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(@r);
$x -> _dng();
return $x;
}
sub bint {
# round towards zero
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Don't modify constant (read-only) objects.
return $x if $x -> modify('bint');
return $x -> bnan(@r) if $x -> is_nan();
if ($x -> is_finite()) {
# if $x has digits after the decimal point
if ($x->{_es} eq '-') {
$x->{_m} = $LIB->_rsft($x->{_m}, $x->{_e}, 10); # remove frac part
$x->{_e} = $LIB->_zero(); # truncate/normalize
$x->{_es} = '+'; # abs e
$x->{sign} = '+' if $LIB->_is_zero($x->{_m}); # avoid -0
}
}
$x -> round(@r);
$x -> _dng();
return $x;
}
###############################################################################
# Other mathematical methods
###############################################################################
sub bgcd {
# GCD -- Euclid's algorithm, variant C (Knuth Vol 3, pg 341 ff)
# Class::method(...) -> Class->method(...)
unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
($_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i &&
$_[0] !~ /^(inf|nan)/i)))
{
#carp "Using ", (caller(0))[3], "() as a function is deprecated;",
# " use is as a method instead";
unshift @_, __PACKAGE__;
}
my ($class, @args) = objectify(0, @_);
# Pre-process list of operands.
for my $arg (@args) {
return $class -> bnan() unless $arg -> is_finite();
}
# Temporarily disable downgrading.
my $dng = $class -> downgrade();
$class -> downgrade(undef);
my $x = shift @args;
$x = $x -> copy(); # bgcd() and blcm() never modify any operands
while (@args) {
my $y = shift @args;
# greatest common divisor
while (! $y -> is_zero()) {
($x, $y) = ($y -> copy(), $x -> copy() -> bmod($y));
}
last if $x -> is_one();
}
$x -> babs();
# Restore downgrading.
$class -> downgrade($dng);
$x -> _dng() if $x -> is_int();
return $x;
}
sub blcm {
# Least Common Multiple
# Class::method(...) -> Class->method(...)
unless (@_ && (defined(blessed($_[0])) && $_[0] -> isa(__PACKAGE__) ||
($_[0] =~ /^[a-z]\w*(?:::[a-z]\w*)*$/i &&
$_[0] !~ /^(inf|nan)/i)))
{
#carp "Using ", (caller(0))[3], "() as a function is deprecated;",
# " use is as a method instead";
unshift @_, __PACKAGE__;
}
my ($class, @args) = objectify(0, @_);
# Pre-process list of operands.
for my $arg (@args) {
return $class -> bnan() unless $arg -> is_finite();
}
for my $arg (@args) {
return $class -> bzero() if $arg -> is_zero();
}
my $x = shift @args;
$x = $x -> copy(); # bgcd() and blcm() never modify any operands
while (@args) {
my $y = shift @args;
my $gcd = $x -> copy() -> bgcd($y);
$x -> bdiv($gcd) -> bmul($y);
}
$x -> babs(); # might downgrade
return $x;
}
###############################################################################
# Object property methods
###############################################################################
sub length {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
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, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# The following line causes a lot of noise in the test suits for
# the Math-BigRat and bignum distributions. Fixme!
#carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
return $x -> bnan(@r) if $x -> is_nan();
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 = $m -> bneg() if $x->{sign} eq '-';
$m;
}
sub exponent {
# return a copy of the exponent
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# The following line causes a lot of noise in the test suits for
# the Math-BigRat and bignum distributions. Fixme!
#carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
return $x -> bnan(@r) if $x -> is_nan();
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, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
if ($x->{sign} !~ /^[+-]$/) {
my $s = $x->{sign};
$s =~ s/^\+//;
my $se = $s;
$se =~ s/^-//;
# +inf => inf and -inf, +inf => inf
return $class -> new($s), $class -> new($se);
}
my $m = Math::BigInt -> bzero();
$m->{value} = $LIB->_copy($x->{_m});
$m = $m -> bneg() if $x->{sign} eq '-';
($m, Math::BigInt -> new($x->{_es} . $LIB->_num($x->{_e})));
}
# Parts used for scientific notation with significand/mantissa and exponent as
# integers. E.g., "12345.6789" is returned as "123456789" (mantissa) and "-4"
# (exponent).
sub sparts {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Not-a-number.
if ($x -> is_nan()) {
my $mant = $class -> bnan(); # mantissa
return $mant unless wantarray; # scalar context
my $expo = $class -> bnan(); # exponent
return $mant, $expo; # list context
}
# Infinity.
if ($x -> is_inf()) {
my $mant = $class -> binf($x->{sign}); # mantissa
return $mant unless wantarray; # scalar context
my $expo = $class -> binf('+'); # exponent
return $mant, $expo; # list context
}
# Finite number.
my $mant = $class -> new($x);
$mant->{_es} = '+';
$mant->{_e} = $LIB->_zero();
$mant -> _dng();
return $mant unless wantarray;
my $expo = $class -> new($x -> {_es} . $LIB->_str($x -> {_e}));
$expo -> _dng();
return $mant, $expo;
}
# Parts used for normalized notation with significand/mantissa as either 0 or a
# number in the semi-open interval [1,10). E.g., "12345.6789" is returned as
# "1.23456789" and "4".
sub nparts {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Not-a-number and Infinity.
return $x -> sparts() if $x -> is_nan() || $x -> is_inf();
# Finite number.
my ($mant, $expo) = $x -> sparts();
if ($mant -> bcmp(0)) {
my ($ndigtot, $ndigfrac) = $mant -> length();
my $expo10adj = $ndigtot - $ndigfrac - 1;
if ($expo10adj > 0) { # if mantissa is not an integer
$mant = $mant -> brsft($expo10adj, 10);
return $mant unless wantarray;
$expo = $expo -> badd($expo10adj);
return $mant, $expo;
}
}
return $mant unless wantarray;
return $mant, $expo;
}
# Parts used for engineering notation with significand/mantissa as either 0 or
# a number in the semi-open interval [1,1000) and the exponent is a multiple of
# 3. E.g., "12345.6789" is returned as "12.3456789" and "3".
sub eparts {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Not-a-number and Infinity.
return $x -> sparts() if $x -> is_nan() || $x -> is_inf();
# Finite number.
my ($mant, $expo) = $x -> nparts();
my $c = $expo -> copy() -> bmod(3);
$mant = $mant -> blsft($c, 10);
return $mant unless wantarray;
$expo = $expo -> bsub($c);
return $mant, $expo;
}
# Parts used for decimal notation, e.g., "12345.6789" is returned as "12345"
# (integer part) and "0.6789" (fraction part).
sub dparts {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Not-a-number.
if ($x -> is_nan()) {
my $int = $class -> bnan();
return $int unless wantarray;
my $frc = $class -> bzero(); # or NaN?
return $int, $frc;
}
# Infinity.
if ($x -> is_inf()) {
my $int = $class -> binf($x->{sign});
return $int unless wantarray;
my $frc = $class -> bzero();
return $int, $frc;
}
# Finite number.
my $int = $x -> copy();
my $frc;
# If the input is an integer.
if ($int->{_es} eq '+') {
$frc = $class -> bzero();
}
# If the input has a fraction part
else {
$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 = $x -> copy() -> bsub($int);
return $int, $frc;
}
$int -> _dng();
return $int unless wantarray;
return $int, $frc;
}
# Fractional parts with the numerator and denominator as integers. E.g.,
# "123.4375" is returned as "1975" and "16".
sub fparts {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# NaN => NaN/NaN
if ($x -> is_nan()) {
return $class -> bnan() unless wantarray;
return $class -> bnan(), $class -> bnan();
}
# ±Inf => ±Inf/1
if ($x -> is_inf()) {
my $numer = $class -> binf($x->{sign});
return $numer unless wantarray;
my $denom = $class -> bone();
return $numer, $denom;
}
# Finite number.
# If we get here, we know that the output is an integer.
$class = $downgrade if $class -> downgrade();
my @flt_parts = ($x->{sign}, $x->{_m}, $x->{_es}, $x->{_e});
my @rat_parts = $class -> _flt_lib_parts_to_rat_lib_parts(@flt_parts);
my $numer = $class -> new($LIB -> _str($rat_parts[1]));
$numer -> bneg() if $rat_parts[0] eq "-";
return $numer unless wantarray;
my $denom = $class -> new($LIB -> _str($rat_parts[2]));
return $numer, $denom;
}
# Given "123.4375", returns "1975", since "123.4375" is "1975/16".
sub numerator {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
return $class -> bnan() if $x -> is_nan();
return $class -> binf($x -> sign()) if $x -> is_inf();
return $class -> bzero() if $x -> is_zero();
# If we get here, we know that the output is an integer.
$class = $downgrade if $class -> downgrade();
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}));
}
}
# Given "123.4375", returns "16", since "123.4375" is "1975/16".
sub denominator {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
return $class -> bnan() if $x -> is_nan();
# If we get here, we know that the output is an integer.
$class = $downgrade if $class -> downgrade();
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, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Inf and NaN
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
return 'inf'; # +inf
}
# Finite number
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->{accuracy}) && ($not_zero)) {
# 123400 => 6, 0.1234 => 4, 0.001234 => 4
my $zeros = $x->{accuracy} - $cad; # cad == 0 => 12340
$zeros = $x->{accuracy} - $len if $cad != $len;
$es .= $dot.'0' x $zeros if $zeros > 0;
} elsif ((($x->{precision} || 0) < 0)) {
# 123400 => 6, 0.1234 => 4, 0.001234 => 6
my $zeros = -$x->{precision} + $cad;
$es .= $dot.'0' x $zeros if $zeros > 0;
}
$es;
}
# Scientific notation with significand/mantissa and exponent as integers, e.g.,
# "12345.6789" is written as "123456789e-4".
sub bsstr {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Inf and NaN
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
return 'inf'; # +inf
}
# Upgrade?
return $x -> _upg() -> bsstr(@r)
if $class -> upgrade() && !$x -> isa(__PACKAGE__);
# Round according to arguments or global settings, if any.
$x = $x -> copy() -> round(@r);
# Finite number
($x->{sign} eq '-' ? '-' : '') . $LIB->_str($x->{_m})
. 'e' . $x->{_es} . $LIB->_str($x->{_e});
}
# Normalized notation, e.g., "12345.6789" is written as "1.23456789e+4".
sub bnstr {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Inf and NaN
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
return 'inf'; # +inf
}
# Upgrade?
return $x -> _upg() -> bnstr(@r)
if $class -> upgrade() && !$x -> isa(__PACKAGE__);
# Finite number
my $str = $x->{sign} eq '-' ? '-' : '';
# Round according to arguments or global settings, if any.
$x = $x -> copy() -> round(@r);
# Get the mantissa and the length of the mantissa.
my $mant = $LIB->_str($x->{_m});
my $mantlen = CORE::length($mant);
if ($mantlen == 1) {
# Not decimal point when the mantissa has length one, i.e., return the
# number 2 as the string "2", not "2.".
$str .= $mant . 'e' . $x->{_es} . $LIB->_str($x->{_e});
} else {
# Compute new exponent where the original exponent is adjusted by the
# length of the mantissa minus one (because the decimal point is after
# one digit).
my ($eabs, $esgn) = $LIB -> _sadd($LIB -> _copy($x->{_e}), $x->{_es},
$LIB -> _new($mantlen - 1), "+");
substr $mant, 1, 0, ".";
$str .= $mant . 'e' . $esgn . $LIB->_str($eabs);
}
return $str;
}
# Engineering notation, e.g., "12345.6789" is written as "12.3456789e+3".
sub bestr {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Inf and NaN
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
return 'inf'; # +inf
}
# Upgrade?
return $x -> _upg() -> bestr(@r)
if $class -> upgrade() && !$x -> isa(__PACKAGE__);
# Round according to arguments or global settings, if any.
$x = $x -> copy() -> round(@r);
# Finite number
my $str = $x->{sign} eq '-' ? '-' : '';
# Get the mantissa, the length of the mantissa, and adjust the exponent by
# the length of the mantissa minus 1 (because the dot is after one digit).
my $mant = $LIB->_str($x->{_m});
my $mantlen = CORE::length($mant);
my ($eabs, $esgn) = $LIB -> _sadd($LIB -> _copy($x->{_e}), $x->{_es},
$LIB -> _new($mantlen - 1), "+");
my $dotpos = 1;
my $mod = $LIB -> _mod($LIB -> _copy($eabs), $LIB -> _new("3"));
unless ($LIB -> _is_zero($mod)) {
if ($esgn eq '+') {
$eabs = $LIB -> _sub($eabs, $mod);
$dotpos += $LIB -> _num($mod);
} else {
my $delta = $LIB -> _sub($LIB -> _new("3"), $mod);
$eabs = $LIB -> _add($eabs, $delta);
$dotpos += $LIB -> _num($delta);
}
}
if ($dotpos < $mantlen) {
substr $mant, $dotpos, 0, ".";
} elsif ($dotpos > $mantlen) {
$mant .= "0" x ($dotpos - $mantlen);
}
$str .= $mant . 'e' . $esgn . $LIB->_str($eabs);
return $str;
}
# Decimal notation, e.g., "12345.6789" (no exponent).
sub bdstr {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
# Inf and NaN
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
return 'inf'; # +inf
}
# Upgrade?
return $x -> _upg() -> bdstr(@r)
if $class -> upgrade() && !$x -> isa(__PACKAGE__);
# Round according to arguments or global settings, if any.
$x = $x -> copy() -> round(@r);
# Finite number
my $mant = $LIB->_str($x->{_m});
my $esgn = $x->{_es};
my $eabs = $LIB -> _num($x->{_e});
my $uintmax = ~0;
my $str = $mant;
if ($esgn eq '+') {
croak("The absolute value of the exponent is too large")
if $eabs > $uintmax;
$str .= "0" x $eabs;
} else {
my $mlen = CORE::length($mant);
my $c = $mlen - $eabs;
my $intmax = ($uintmax - 1) / 2;
croak("The absolute value of the exponent is too large")
if (1 - $c) > $intmax;
$str = "0" x (1 - $c) . $str if $c <= 0;
substr($str, -$eabs, 0) = '.';
}
return $x->{sign} eq '-' ? '-' . $str : $str;
}
# Fractional notation, e.g., "123.4375" is written as "1975/16".
sub bfstr {
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Inf and NaN
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
return 'inf'; # +inf
}
# Upgrade?
return $x -> _upg() -> bfstr(@r)
if $class -> upgrade() && !$x -> isa(__PACKAGE__);
# Finite number
my $str = $x->{sign} eq '-' ? '-' : '';
if ($x->{_es} eq '+') {
$str .= $LIB -> _str($x->{_m}) . ("0" x $LIB -> _num($x->{_e}));
} else {
my @flt_parts = ($x->{sign}, $x->{_m}, $x->{_es}, $x->{_e});
my @rat_parts = $class -> _flt_lib_parts_to_rat_lib_parts(@flt_parts);
$str = $LIB -> _str($rat_parts[1]) . "/" . $LIB -> _str($rat_parts[2]);
$str = "-" . $str if $rat_parts[0] eq "-";
}
return $str;
}
sub to_hex {
# return number as hexadecimal string (only for integers defined)
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Inf and NaN
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
return 'inf'; # +inf
}
# Upgrade?
return $x -> _upg() -> to_hex(@r)
if $class -> upgrade() && !$x -> isa(__PACKAGE__);
# Finite number
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, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Inf and NaN
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
return 'inf'; # +inf
}
# Upgrade?
return $x -> _upg() -> to_oct(@r)
if $class -> upgrade() && !$x -> isa(__PACKAGE__);
# Finite number
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, @r) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# Inf and NaN
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x -> is_inf("+"); # -inf, NaN
return 'inf'; # +inf
}
# Upgrade?
return $x -> _upg() -> to_bin(@r)
if $class -> upgrade() && !$x -> isa(__PACKAGE__);
# Finite number
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_bytes {
# return a byte string
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
croak("to_bytes() requires a finite, non-negative integer")
if $x -> is_neg() || ! $x -> is_int();
return $x -> _upg() -> to_bytes(@r)
if $class -> upgrade() && !$x -> isa(__PACKAGE__);
croak("to_bytes() requires a newer version of the $LIB library.")
unless $LIB -> can('_to_bytes');
return $LIB->_to_bytes($LIB -> _lsft($x->{_m}, $x->{_e}, 10));
}
sub to_ieee754 {
my ($class, $x, $format, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
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 = $mant -> bmul($binv -> copy() -> bpow($expo));
} elsif ($expo_est < 0) {
my $expo_abs = $expo -> copy() -> bneg();
$mant = $mant -> bmul($b -> copy() -> bpow($expo_abs));
}
# Final adjustment of the estimate above.
while ($mant >= $b && $expo <= $emax) {
$mant = $mant -> bmul($binv);
$expo = $expo -> binc();
}
while ($mant < $one && $expo >= $emin) {
$mant = $mant -> bmul($b);
$expo = $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 = $mant -> bmul($const);
$mant = $mant -> bfround(0);
# If the mantissa overflowed, encode as the smallest normal
# number.
if ($mant == $const -> bmul($b)) {
$mant = $mant -> bzero();
$expo = $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 = $mant -> bdec();
my $const = $class -> new($b) -> bpow($t);
$mant = $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 = $mant -> bzero();
$expo = $expo -> binc();
}
}
}
$expo = $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 to_fp80 {
my ($class, $x, $format, @r) = ref($_[0]) ? (ref($_[0]), @_)
: objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
# The maximum exponent, minimum exponent, and exponent bias.
my $emax = Math::BigFloat -> new("16383");
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(64) -> bdec();
} 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 = $mant -> bmul($binv -> copy() -> bpow($expo));
} elsif ($expo_est < 0) {
my $expo_abs = $expo -> copy() -> bneg();
$mant = $mant -> bmul($b -> copy() -> bpow($expo_abs));
}
# Final adjustment of the estimate above.
while ($mant >= $b && $expo <= $emax) {
$mant = $mant -> bmul($binv);
$expo = $expo -> binc();
}
while ($mant < $one && $expo >= $emin) {
$mant = $mant -> bmul($b);
$expo = $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(62);
$mant -> bmul($const) -> bfround(0);
# If the mantissa overflowed, encode as the smallest normal number.
if ($mant == $const -> bmul($b)) {
$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.
my $const = $class -> new($b) -> bpow(63);
$mant -> bmul($const) -> bfround(0);
# If the mantissa overflowed, encode as the next larger value. If
# this caused the exponent to overflow, encode as infinity.
if ($mant == $const -> copy() -> bmul($b)) {
$expo -> binc();
if ($expo > $emax) {
$mant = $class -> bzero();
} else {
$mant = $const;
}
}
}
}
$expo = $expo -> badd($bias); # add bias
my $signbit = "$sign";
my $mantbits = $mant -> to_bin();
$mantbits = ("0" x (64 - CORE::length($mantbits))) . $mantbits;
my $expobits = $expo -> to_bin();
$expobits = ("0" x (15 - CORE::length($expobits))) . $expobits;
my $bin = $signbit . $expobits . $mantbits;
return pack "B*", $bin;
}
sub as_hex {
# return number as hexadecimal string (only for integers defined)
my (undef, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
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 (undef, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
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 (undef, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
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 (undef, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
carp "Rounding is not supported for ", (caller(0))[3], "()" if @r;
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 @a; # unrecognized arguments
my @import = ();
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;
}
# Fall-back accuracy.
if ($param eq 'div_scale') {
$class -> div_scale(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 library was actually loaded
$LIB = Math::BigInt -> config('lib');
$class -> SUPER::import(@a); # for subclasses
$class -> export_to_level(1, $class, @a) if @a; # need this, too
}
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 _|
# scale used in intermediate computations
my $scaleup = $scale + 4;
my ($v, $u, $numer, $denom, $factor, $f);
$v = $x -> copy();
$v = $v -> binc(); # v = x+1
$x = $x -> bdec();
$u = $x -> copy(); # u = x-1; x = x-1
$x = $x -> bdiv($v, $scaleup); # first term: u/v
$numer = $u -> copy(); # numerator
$denom = $v -> copy(); # denominator
$u = $u -> bmul($u); # u^2
$v = $v -> bmul($v); # v^2
$numer = $numer -> bmul($u); # u^3
$denom = $denom -> bmul($v); # v^3
$factor = $class -> new(3);
$f = $class -> new(2);
while (1) {
my $next = $numer -> copy() -> bround($scaleup)
-> bdiv($denom -> copy() -> bmul($factor) -> bround($scaleup), $scaleup);
$next->{accuracy} = undef;
$next->{precision} = undef;
my $x_prev = $x -> copy();
$x = $x -> badd($next);
last if $x -> bacmp($x_prev) == 0;
# calculate things for the next term
$numer = $numer -> bmul($u);
$denom = $denom -> bmul($v);
$factor = $factor -> badd($f);
}
$x = $x -> bmul($f); # $x *= 2
$x = $x -> bround($scale);
}
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 the number of digits before the dot, i.e., 1 + floor(log10(x)):
# 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?
# No upgrading or downgrading in the intermediate computations.
my $upg = $class -> upgrade();
my $dng = $class -> downgrade();
$class -> upgrade(undef);
$class -> downgrade(undef);
# 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 = $x -> bzero();
$x = $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 = $x -> bzero();
$x = $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 = $x -> bzero();
$x = $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;
# 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
# 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 = $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 = $l_10->_log($scale); # scale+4, actually
# log(1.25) + log(2) + log(2) + log(2):
$l_10 = $l_10 -> badd($l_2);
$l_10 = $l_10 -> badd($l_2);
$l_10 = $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 = $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}) =
$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 = $x -> bmul($two);
}
while ($x -> bacmp($two) >= 0) { # X >= 2
$twos++;
$x = $x -> bdiv($two, $scale+4); # keep all digits
}
$x = $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
$l_2 = $two -> copy();
$l_2 = $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 = $l_2 -> bmul($twos); # * -2 => subtract, * 2 => add
} else {
undef $l_2;
}
$x = $x->_log($scale); # need to do the "normal" way
$x = $x -> badd($l_10) if defined $l_10; # correct it by ln(10)
$x = $x -> badd($l_2) if defined $l_2; # and maybe by ln(2)
# Restore globals
$class -> upgrade($upg);
$class -> downgrade($dng);
# all done, $x contains now the result
$x;
}
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.
my $ab = $class -> accuracy();
my $pb = $class -> precision();
$class -> accuracy(undef);
$class -> precision(undef);
# Disabling upgrading and downgrading is no longer necessary to avoid an
# infinite recursion, but it avoids unnecessary upgrading and downgrading
# in the intermediate computations.
my $upg = $class -> upgrade();
my $dng = $class -> downgrade();
$class -> upgrade(undef);
$class -> downgrade(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.
$x->{accuracy} = undef;
$x->{precision} = undef;
my ($limit, $v, $u, $below, $factor, $next, $over);
$u = $x -> copy() -> blog(undef, $scale) -> bmul($y);
my $do_invert = ($u->{sign} eq '-');
$u = $u -> bneg() if $do_invert;
$v = $class -> bone(); # 1
$factor = $class -> new(2); # 2
$x = $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 = $x -> badd($next);
# calculate things for the next term
$over *= $u;
$below *= $factor;
$factor = $factor -> binc();
last if $x->{sign} !~ /^[-+]$/;
}
if ($do_invert) {
my $x_copy = $x -> copy();
$x = $x -> bone -> bdiv($x_copy, $scale);
}
# shortcut to not run through _find_round_parameters again
if (defined $params[0]) {
$x = $x -> bround($params[0], $params[2]); # then round accordingly
} else {
$x = $x -> bfround($params[1], $params[2]); # then round accordingly
}
if ($fallback) {
# clear a/p after round, since user did not request it
$x->{accuracy} = undef;
$x->{precision} = undef;
}
# Restore globals. We need to do it like this, because setting one
# undefines the other.
if (defined $ab) {
$class -> accuracy($ab);
} else {
$class -> precision($pb);
}
$class -> upgrade($upg);
$class -> downgrade($dng);
$x;
}
# These functions are only provided for backwards compabibility so that old
# version of Math::BigRat etc. don't complain about missing them.
sub _e_add {
my ($x, $y, $xs, $ys) = @_;
return $LIB -> _sadd($x, $xs, $y, $ys);
}
sub _e_sub {
my ($x, $y, $xs, $ys) = @_;
return $LIB -> _ssub($x, $xs, $y, $ys);
}
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($n); # set accuracy
Math::BigFloat->accuracy(); # get accuracy
Math::BigFloat->precision($n); # set precision
Math::BigFloat->precision(); # get precision
Math::BigFloat->round_mode($m); # set rounding mode, must be
# 'even', 'odd', '+inf', '-inf',
# 'zero', 'trunc', or 'common'
Math::BigFloat->round_mode(); # get class rounding mode
Math::BigFloat->div_scale($n); # set fallback accuracy
Math::BigFloat->div_scale(); # get fallback accuracy
Math::BigFloat->trap_inf($b); # trap infinities or not
Math::BigFloat->trap_inf(); # get trap infinities status
Math::BigFloat->trap_nan($b); # trap NaNs or not
Math::BigFloat->trap_nan(); # get trap NaNs status
Math::BigFloat->config($par, $val); # set configuration parameter
Math::BigFloat->config($par); # get configuration parameter
Math::BigFloat->config(); # get hash with configuration
Math::BigFloat->config("lib"); # get name of backend library
# Generic constructor method (always returns a new object)
$x = Math::BigFloat->new($str); # defaults to 0
$x = Math::BigFloat->new('256'); # from decimal
$x = Math::BigFloat->new('0256'); # from decimal
$x = Math::BigFloat->new('0xcafe'); # from hexadecimal
$x = Math::BigFloat->new('0x1.cafep+7'); # from hexadecimal
$x = Math::BigFloat->new('0o377'); # from octal
$x = Math::BigFloat->new('0o1.3571p+6'); # from octal
$x = Math::BigFloat->new('0b101'); # from binary
$x = Math::BigFloat->new('0b1.101p+3'); # from binary
# Specific constructor methods (no prefix needed; when used as
# instance method, the value is assigned to the invocand)
$x = Math::BigFloat->from_dec('234'); # from decimal
$x = Math::BigFloat->from_hex('c.afep+3'); # from hexadecimal
$x = Math::BigFloat->from_hex('cafe'); # from hexadecimal
$x = Math::BigFloat->from_oct('1.3267p-4'); # from octal
$x = Math::BigFloat->from_oct('377'); # from octal
$x = Math::BigFloat->from_bin('0b1.1001p-4'); # from binary
$x = Math::BigFloat->from_bin('0101'); # from binary
$x = Math::BigFloat->from_bytes($bytes); # from byte string
$x = Math::BigFloat->from_base('why', 36); # from any base
$x = Math::BigFloat->from_ieee754($b, $fmt); # from IEEE-754 bytes
$x = Math::BigFloat->from_fp80($b); # from x86 80-bit
$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
$y = $x->as_float(); # return as a Math::BigFloat
$y = $x->as_rat(); # return as a Math::BigRat
# Boolean methods (these don't modify the invocand)
$x->is_zero(); # true if $x is 0
$x->is_one(); # true if $x is +1
$x->is_one("+"); # true if $x is +1
$x->is_one("-"); # true if $x is -1
$x->is_inf(); # true if $x is +inf or -inf
$x->is_inf("+"); # true if $x is +inf
$x->is_inf("-"); # true if $x is -inf
$x->is_nan(); # true if $x is NaN
$x->is_finite(); # true if -inf < $x < inf
$x->is_positive(); # true if $x > 0
$x->is_pos(); # true if $x > 0
$x->is_negative(); # true if $x < 0
$x->is_neg(); # true if $x < 0
$x->is_non_positive() # true if $x <= 0
$x->is_non_negative() # true if $x >= 0
$x->is_odd(); # true if $x is odd
$x->is_even(); # true if $x is even
$x->is_int(); # true if $x is an integer
# Comparison methods (these don't modify the invocand)
$x->bcmp($y); # compare numbers (undef, < 0, == 0, > 0)
$x->bacmp($y); # compare abs values (undef, < 0, == 0, > 0)
$x->beq($y); # true if $x == $y
$x->bne($y); # true if $x != $y
$x->blt($y); # true if $x < $y
$x->ble($y); # true if $x <= $y
$x->bgt($y); # true if $x > $y
$x->bge($y); # true if $x >= $y
# Arithmetic methods (these modify the invocand)
$x->bneg(); # negation
$x->babs(); # absolute value
$x->bsgn(); # sign function (-1, 0, 1, or NaN)
$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
$x->bmod($y); # modulus (x % y)
$x->bmodinv($mod); # modular multiplicative inverse
$x->bmodpow($y, $mod); # modular exponentiation (($x ** $y) % $mod)
$x->btdiv($y); # division (truncated), set $x to quotient
$x->btmod($y); # modulus (truncated)
$x->binv() # inverse (1/$x)
$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->bilog2(); # log2($x) rounded down to nearest int
$x->bilog10(); # log10($x) rounded down to nearest int
$x->bclog2(); # log2($x) rounded up to nearest int
$x->bclog10(); # log10($x) rounded up to nearest int
$x->bnok($y); # combinations (binomial coefficient n over k)
$x->bperm($y); # permutations
$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->bdfac(); # double factorial of $x ($x*($x-2)*($x-4)*...)
$x->btfac(); # triple factorial of $x ($x*($x-3)*($x-6)*...)
$x->bmfac($k); # $k'th multi-factorial of $x ($x*($x-$k)*...)
$x->bfib($k); # $k'th Fibonacci number
$x->blucas($k); # $k'th Lucas number
$x->blsft($n); # left shift $n places in base 2
$x->blsft($n, $b); # left shift $n places in base $b
$x->brsft($n); # right shift $n places in base 2
$x->brsft($n, $b); # right shift $n places in base $b
# Bitwise methods (these modify the invocand)
$x->bblsft($y); # bitwise left shift
$x->bbrsft($y); # bitwise right shift
$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 (these modify the invocand)
$x->round($A, $P, $R); # round to accuracy or precision using
# rounding mode $R
$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 (these don't modify the invocand)
$x->bgcd($y); # greatest common divisor
$x->blcm($y); # least common multiple
# Object property methods (these don't 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
$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 (these don't 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 (no padding)
$x->bfstr(); # string in fractional notation
$x->to_hex(); # as signed hexadecimal string
$x->to_bin(); # as signed binary string
$x->to_oct(); # as signed octal string
$x->to_bytes(); # as byte string
$x->to_ieee754($fmt); # to bytes encoded according to IEEE 754-2008
$x->to_fp80(); # encode value in x86 80-bit format
$x->as_hex(); # as signed hexadecimal string with "0x" prefix
$x->as_bin(); # as signed binary string with "0b" prefix
$x->as_oct(); # as signed octal string with "0" prefix
# Other conversion methods (these don't modify the invocand)
$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 L,
L, L, etc.
return true or false.
Comparison operators L and
L) 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_dec()
$x -> from_hex("314159");
$x = Math::BigInt -> from_hex("314159");
Interpret input as a decimal. It is equivalent to new(), but does not accept
anything but strings representing finite, decimal numbers.
=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_bytes()
$x = Math::BigFloat->from_bytes("\xf3\x6b"); # $x = 62315
Interpret the input as a byte string, assuming big endian byte order. The
output is always a non-negative, finite integer.
See L.
=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, $xr, $xh, and $xb below are 3.141592...
$dbl = unpack "d>", "\x40\x09\x21\xfb\x54\x44\x2d\x18";
$raw = "\x40\x09\x21\xfb\x54\x44\x2d\x18"; # raw bytes
$xr = Math::BigFloat -> from_ieee754($raw, "binary64");
$hex = "400921fb54442d18";
$xh = Math::BigFloat -> from_ieee754($hex, "binary64");
$bin = "0100000000001001001000011111101101010100010001000010110100011000";
$xb = Math::BigFloat -> from_ieee754($bin, "binary64");
Supported formats are all IEEE 754 binary formats: "binary16", "binary32",
"binary64", "binary128", "binary160", "binary192", "binary224", "binary256",
etc. where the number of bits is a multiple of 32 for all formats larger than
"binary128". Aliases are "half" ("binary16"), "single" ("binary32"), "double"
("binary64"), "quadruple" ("binary128"), "octuple" ("binary256"), and
"sexdecuple" ("binary512").
See also L.
=item from_fp80()
Interpret the input as a value encoded as an x86 80-bit floating point number. The input
can be given as a 10 character byte string, 20 character hex string, or 80 character binary string. The input is
assumed to be in big-endian byte-order.
# Both $xr, $xh, and $xb below are 3.141592...
$dbl = unpack "d>", "\x40\x09\x21\xfb\x54\x44\x2d\x18";
$raw = "\x40\x00\xc9\x0f\xda\xa2\x21\x68\xc2\x35"; # raw bytes
$xr = Math::BigFloat -> from_fp80($raw);
$hex = "4000c90fdaa22168c235";
$xh = Math::BigFloat -> from_fp80($hex);
$bin = "0100000000000000110010010000111111011010"
. "1010001000100001011010001100001000110101";
$xb = Math::BigFloat -> from_fp80($bin);
See also L.
=item from_base()
See L.
=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).
=item as_int()
$y = $x -> as_int(); # $y is a Math::BigInt
Returns $x as a Math::BigInt object regardless of upgrading and downgrading. If
$x is finite, but not an integer, $x is truncated.
=item as_rat()
$y = $x -> as_rat(); # $y is a Math::BigRat
Returns $x a Math::BigRat object regardless of upgrading and downgrading. The
invocand is not modified.
=item as_float()
$y = $x -> as_float(); # $y is a Math::BigFloat
Returns $x a Math::BigFloat object regardless of upgrading and downgrading. The
invocand is not modified.
=back
=head2 Arithmetic methods
=over
=item bdiv()
$x->bdiv($y); # set $x to quotient
($q, $r) = $x->bdiv($y); # also remainder
This is an alias for L.
=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 bfdiv()
$q = $x->bfdiv($y);
($q, $r) = $x->bfdiv($y);
In scalar context, divides $x by $y and returns the result to the given
accuracy or precision or the default accuracy. In list context, does floored
division (F-division), returning an integer $q and a remainder $r
$q = floor($x / $y)
$r = $x - $q * $y
so that the following relationship always holds
$x = $q * $y + $r
The remainer (modulo) is equal to what is returned by C<< $x->bmod($y) >>.
=item binv()
$x->binv();
Invert the value of $x, i.e., compute 1/$x.
=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 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()
See L.
=item bperm()
See L.
=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 bgcd()
$x -> bgcd($y); # GCD of $x and $y
$x -> bgcd($y, $z, ...); # GCD of $x, $y, $z, ...
Returns the greatest common divisor (GCD), which is the number with the largest
absolute value such that $x/$gcd, $y/$gcd, ... is an integer. For example, when
the operands are 0.8 and 1.2, the GCD is 0.4. This is a generalisation of the
ordinary GCD for integers. See L.
=back
=head2 String conversion methods
=over
=item bstr()
my $x = Math::BigRat->new('8/4');
print $x->bstr(), "\n"; # prints 1/2
Returns a string representing the number.
=item bsstr()
See L.
=item bnstr()
See L.
=item bestr()
See L.
=item bdstr()
See L.
=item to_bytes()
See L.
=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, 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 L 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 L method 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
L:
$x = Math::BigFloat->new(2.5);
$y = $x->as_number('odd'); # $y = 3
=head1 NUMERIC LITERALS
After C, L, L, etc. return true
or false.
Comparison operators L and L) return -1, 0, 1, or undef.
=head1 METHODS
=head2 Configuration methods
Each of the methods below (except L, L and
L) accepts three additional parameters. These arguments C<$A>,
C<$P> and C<$R> are C, C and C. Please see the
section about L for more information.
Setting a class variable effects all object instance that are created
afterwards.
=over
=item accuracy()
Math::BigInt->accuracy(5); # set class accuracy
$x->accuracy(5); # set instance accuracy
$A = Math::BigInt->accuracy(); # get class accuracy
$A = $x->accuracy(); # get instance accuracy
Set or get the accuracy, i.e., the number of significant digits. The accuracy
must be an integer. If the accuracy is set to C, no rounding is done.
Alternatively, one can round the results explicitly using one of L,
L or L or by passing the desired accuracy to the method
as an additional parameter:
my $x = Math::BigInt->new(30000);
my $y = Math::BigInt->new(7);
print scalar $x->copy()->bdiv($y, 2); # prints 4300
print scalar $x->copy()->bdiv($y)->bround(2); # prints 4300
Please see the section about L for further details.
$y = Math::BigInt->new(1234567); # $y is not rounded
Math::BigInt->accuracy(4); # set class accuracy to 4
$x = Math::BigInt->new(1234567); # $x is rounded automatically
print "$x $y"; # prints "1235000 1234567"
print $x->accuracy(); # prints "4"
print $y->accuracy(); # also prints "4", since
# class accuracy is 4
Math::BigInt->accuracy(5); # set class accuracy to 5
print $x->accuracy(); # prints "4", since instance
# accuracy is 4
print $y->accuracy(); # prints "5", since no instance
# accuracy, and class accuracy is 5
Note: Each class has it's own globals separated from Math::BigInt, but it is
possible to subclass Math::BigInt and make the globals of the subclass aliases
to the ones from Math::BigInt.
=item precision()
Math::BigInt->precision(-2); # set class precision
$x->precision(-2); # set instance precision
$P = Math::BigInt->precision(); # get class precision
$P = $x->precision(); # get instance precision
Set or get the precision, i.e., the place to round relative to the decimal
point. The precision must be a integer. Setting the precision to $P means that
each number is rounded up or down, depending on the rounding mode, to the
nearest multiple of 10**$P. If the precision is set to C, no rounding is
done.
You might 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.
Please see the section about L for further details.
$y = Math::BigInt->new(1234567); # $y is not rounded
Math::BigInt->precision(4); # set class precision to 4
$x = Math::BigInt->new(1234567); # $x is rounded automatically
print $x; # prints "1230000"
Note: Each class has its own globals separated from Math::BigInt, but it is
possible to subclass Math::BigInt and make the globals of the subclass aliases
to the ones from Math::BigInt.
=item round_mode()
Set/get the rounding mode.
=item div_scale()
Set/get the fallback accuracy. This is the accuracy used when neither accuracy
nor precision is set explicitly. It is used when a computation might otherwise
attempt to return an infinite number of digits.
=item trap_inf()
Set/get the value determining whether infinities should cause a fatal error or
not.
=item trap_nan()
Set/get the value determining whether NaNs should cause a fatal error or not.
=item upgrade()
Set/get the class for upgrading. When a computation might result in a
non-integer, the operands are upgraded to this class. This is used for instance
by L. The default is C, i.e., no upgrading.
# with no upgrading
$x = Math::BigInt->new(12);
$y = Math::BigInt->new(5);
print $x / $y, "\n"; # 2 as a Math::BigInt
# with upgrading to Math::BigFloat
Math::BigInt -> upgrade("Math::BigFloat");
print $x / $y, "\n"; # 2.4 as a Math::BigFloat
# with upgrading to Math::BigRat (after loading Math::BigRat)
Math::BigInt -> upgrade("Math::BigRat");
print $x / $y, "\n"; # 12/5 as a Math::BigRat
=item downgrade()
Set/get the class for downgrading. The default is C, i.e., no
downgrading. Downgrading is not done by Math::BigInt.
=item modify()
$x->modify('bpowd');
This method returns 0 if the object can be modified with the given operation,
or 1 if not.
This is used for instance by L.
=item config()
Math::BigInt->config("trap_nan" => 1); # set
$accu = Math::BigInt->config("accuracy"); # get
Set or get class variables. Read-only parameters are marked as RO. Read-write
parameters are marked as RW. The following parameters are supported.
Parameter RO/RW Description
Example
============================================================
lib RO Name of the math backend library
Math::BigInt::Calc
lib_version RO Version of the math backend library
0.30
class RO The class of config you just called
Math::BigRat
version RO version number of the class you used
0.10
upgrade RW To which class numbers are upgraded
undef
downgrade RW To which class numbers are downgraded
undef
precision RW Global precision
undef
accuracy RW Global accuracy
undef
round_mode RW Global round mode
even
div_scale RW Fallback accuracy for division etc.
40
trap_nan RW Trap NaNs
undef
trap_inf RW Trap +inf/-inf
undef
=back
=head2 Constructor methods
=over
=item new()
$x = Math::BigInt->new($str,$A,$P,$R);
Creates a new Math::BigInt object from a scalar or another Math::BigInt object.
The input is accepted as decimal, hexadecimal (with leading '0x'), octal (with
leading ('0o') or binary (with leading '0b').
See L for more info on accepted input formats.
=item from_dec()
$x = Math::BigInt->from_dec("314159"); # input is decimal
Interpret input as a decimal. It is equivalent to L, but does not
accept anything but strings representing finite, decimal numbers.
=item from_hex()
$x = Math::BigInt->from_hex("0xcafe"); # input is hexadecimal
Interpret input as a hexadecimal string. A "0x" or "x" prefix is optional. A
single underscore character may be placed right after the prefix, if present,
or between any two digits. If the input is invalid, a NaN is returned.
=item from_oct()
$x = Math::BigInt->from_oct("0775"); # input is octal
Interpret the input as an octal string and return the corresponding value. A
"0" (zero) prefix is optional. A single underscore character may be placed
right after the prefix, if present, or between any two digits. If the input is
invalid, a NaN is returned.
=item from_bin()
$x = Math::BigInt->from_bin("0b10011"); # input is binary
Interpret the input as a binary string. A "0b" or "b" prefix is optional. A
single underscore character may be placed right after the prefix, if present,
or between any two digits. If the input is invalid, a NaN is returned.
=item from_bytes()
$x = Math::BigInt->from_bytes("\xf3\x6b"); # $x = 62315
Interpret the input as a byte string, assuming big endian byte order. The
output is always a non-negative, finite integer.
In some special cases, L matches the conversion done by
unpack():
$b = "\x4e"; # one char byte string
$x = Math::BigInt->from_bytes($b); # = 78
$y = unpack "C", $b; # ditto, but scalar
$b = "\xf3\x6b"; # two char byte string
$x = Math::BigInt->from_bytes($b); # = 62315
$y = unpack "S>", $b; # ditto, but scalar
$b = "\x2d\xe0\x49\xad"; # four char byte string
$x = Math::BigInt->from_bytes($b); # = 769673645
$y = unpack "L>", $b; # ditto, but scalar
$b = "\x2d\xe0\x49\xad\x2d\xe0\x49\xad"; # eight char byte string
$x = Math::BigInt->from_bytes($b); # = 3305723134637787565
$y = unpack "Q>", $b; # ditto, but scalar
=item from_ieee754()
# set $x to 314159
$x = Math::BigInt -> from_ieee754("40490fdb", "binary32");
Interpret the input as a value encoded as described in IEEE754-2008. NaN is
returned if the value is neither +/-infinity nor an integer.
See L.
=item from_fp80()
# set $x to 314159
$x = Math::BigInt -> from_fp80("40119965e00000000000");
Interpret the input as a value encoded in the x86 extended-precision 80-bit
format.
See L.
=item from_base()
Given a string, a base, and an optional collation sequence, interpret the
string as a number in the given base. The collation sequence describes the
value of each character in the string.
If a collation sequence is not given, a default collation sequence is used. If
the base is less than or equal to 36, the collation sequence is the string
consisting of the 36 characters "0" to "9" and "A" to "Z". In this case, the
letter case in the input is ignored. If the base is greater than 36, and
smaller than or equal to 62, the collation sequence is the string consisting of
the 62 characters "0" to "9", "A" to "Z", and "a" to "z". A base larger than 62
requires the collation sequence to be specified explicitly.
These examples show standard binary, octal, and hexadecimal conversion. All
cases return 250.
$x = Math::BigInt->from_base("11111010", 2);
$x = Math::BigInt->from_base("372", 8);
$x = Math::BigInt->from_base("fa", 16);
When the base is less than or equal to 36, and no collation sequence is given,
the letter case is ignored, so both of these also return 250:
$x = Math::BigInt->from_base("6Y", 16);
$x = Math::BigInt->from_base("6y", 16);
When the base greater than 36, and no collation sequence is given, the default
collation sequence contains both uppercase and lowercase letters, so
the letter case in the input is not ignored:
$x = Math::BigInt->from_base("6S", 37); # $x is 250
$x = Math::BigInt->from_base("6s", 37); # $x is 276
$x = Math::BigInt->from_base("121", 3); # $x is 16
$x = Math::BigInt->from_base("XYZ", 36); # $x is 44027
$x = Math::BigInt->from_base("Why", 42); # $x is 58314
The collation sequence can be any set of unique characters. These two cases
are equivalent
$x = Math::BigInt->from_base("100", 2, "01"); # $x is 4
$x = Math::BigInt->from_base("|--", 2, "-|"); # $x is 4
=item from_base_num()
Returns a new Math::BigInt object given an array of values and a base. This
method is equivalent to L, but works on numbers in an array
rather than characters in a string. Unlike L, all input values
may be arbitrarily large.
$x = Math::BigInt->from_base_num([1, 1, 0, 1], 2) # $x is 13
$x = Math::BigInt->from_base_num([3, 125, 39], 128) # $x is 65191
=item bzero()
$x = Math::BigInt->bzero();
$x->bzero();
Returns a new Math::BigInt object representing zero. If used as an instance
method, assigns the value to the invocand.
=item bone()
$x = Math::BigInt->bone(); # +1
$x = Math::BigInt->bone("+"); # +1
$x = Math::BigInt->bone("-"); # -1
$x->bone(); # +1
$x->bone("+"); # +1
$x->bone('-'); # -1
Creates a new Math::BigInt object representing one. The optional argument is
either '-' or '+', indicating whether you want plus one or minus one. If used
as an instance method, assigns the value to the invocand.
=item binf()
$x = Math::BigInt->binf($sign);
Creates a new Math::BigInt object representing infinity. The optional argument
is either '-' or '+', indicating whether you want infinity or minus infinity.
If used as an instance method, assigns the value to the invocand.
$x->binf();
$x->binf('-');
=item bnan()
$x = Math::BigInt->bnan();
Creates a new Math::BigInt object representing NaN (Not A Number). If used as
an instance method, assigns the value to the invocand.
$x->bnan();
=item bpi()
$x = Math::BigInt->bpi(100); # 3
$x->bpi(100); # 3
Creates a new Math::BigInt object representing PI. If used as an instance
method, assigns the value to the invocand. With Math::BigInt this always
returns 3.
If upgrading is in effect, returns PI, rounded to N digits with the current
rounding mode:
use Math::BigFloat;
use Math::BigInt upgrade => "Math::BigFloat";
print Math::BigInt->bpi(3), "\n"; # 3.14
print Math::BigInt->bpi(100), "\n"; # 3.1415....
=item copy()
$x->copy(); # make a true copy of $x (unlike $y = $x)
=item as_int()
$y = $x -> as_int(); # $y is a Math::BigInt
Returns $x as a Math::BigInt object regardless of upgrading and downgrading. If
$x is finite, but not an integer, $x is truncated.
=item as_rat()
$y = $x -> as_rat(); # $y is a Math::BigRat
Returns $x a Math::BigRat object regardless of upgrading and downgrading. The
invocand is not modified.
=item as_float()
$y = $x -> as_float(); # $y is a Math::BigFloat
Returns $x a Math::BigFloat object regardless of upgrading and downgrading. The
invocand is not modified.
=back
=head2 Boolean methods
None of these methods modify the invocand object.
=over
=item is_zero()
$x->is_zero(); # true if $x is 0
Returns true if the invocand is zero and false otherwise.
=item is_one()
$x->is_one(); # true if $x is +1
$x->is_one("+"); # ditto
$x->is_one("-"); # true if $x is -1
Returns true if the invocand is one and false otherwise.
=item is_finite()
$x->is_finite(); # true if $x is not +inf, -inf or NaN
Returns true if the invocand is a finite number, i.e., it is neither +inf,
-inf, nor NaN.
=item is_inf()
$x->is_inf(); # true if $x is +inf or -inf
$x->is_inf("+"); # true if $x is +inf
$x->is_inf("-"); # true if $x is -inf
Returns true if the invocand is infinite and false otherwise.
=item is_nan()
$x->is_nan(); # true if $x is NaN
=item is_positive()
=item is_pos()
$x->is_positive(); # true if > 0
$x->is_pos(); # ditto
Returns true if the invocand is positive and false otherwise. A C is
neither positive nor negative.
=item is_negative()
=item is_neg()
$x->is_negative(); # true if < 0
$x->is_neg(); # ditto
Returns true if the invocand is negative and false otherwise. A C is
neither positive nor negative.
=item is_non_positive()
$x->is_non_positive(); # true if <= 0
Returns true if the invocand is negative or zero.
=item is_non_negative()
$x->is_non_negative(); # true if >= 0
Returns true if the invocand is positive or zero.
=item is_odd()
$x->is_odd(); # true if odd, false for even
Returns true if the invocand is odd and false otherwise. C, C<+inf>, and
C<-inf> are neither odd nor even.
=item is_even()
$x->is_even(); # true if $x is even
Returns true if the invocand is even and false otherwise. C, C<+inf>,
C<-inf> are not integers and are neither odd nor even.
=item is_int()
$x->is_int(); # true if $x is an integer
Returns true if the invocand is an integer and false otherwise. C,
C<+inf>, C<-inf> are not integers.
=back
=head2 Comparison methods
None of these methods modify the invocand object. Note that a C is neither
less than, greater than, or equal to anything else, even a C.
=over
=item bcmp()
$x->bcmp($y);
Returns -1, 0, 1 depending on whether $x is less than, equal to, or grater than
$y. Returns undef if any operand is a NaN.
=item bacmp()
$x->bacmp($y);
Returns -1, 0, 1 depending on whether the absolute value of $x is less than,
equal to, or grater than the absolute value of $y. Returns undef if any operand
is a NaN.
=item beq()
$x -> beq($y);
Returns true if and only if $x is equal to $y, and false otherwise.
=item bne()
$x -> bne($y);
Returns true if and only if $x is not equal to $y, and false otherwise.
=item blt()
$x -> blt($y);
Returns true if and only if $x is equal to $y, and false otherwise.
=item ble()
$x -> ble($y);
Returns true if and only if $x is less than or equal to $y, and false
otherwise.
=item bgt()
$x -> bgt($y);
Returns true if and only if $x is greater than $y, and false otherwise.
=item bge()
$x -> bge($y);
Returns true if and only if $x is greater than or equal to $y, and false
otherwise.
=back
=head2 Arithmetic methods
These methods modify the invocand object and returns it.
=over
=item bneg()
$x->bneg();
Negate the number, e.g. change the sign between '+' and '-', or between '+inf'
and '-inf', respectively. Does nothing for NaN or zero.
=item babs()
$x->babs();
Set the number to its absolute value, e.g. change the sign from '-' to '+'
and from '-inf' to '+inf', respectively. Does nothing for NaN or positive
numbers.
=item bsgn()
$x->bsgn();
Signum function. Set the number to -1, 0, or 1, depending on whether the
number is negative, zero, or positive, respectively. Does not modify NaNs.
=item bnorm()
$x->bnorm(); # normalize (no-op)
Normalize the number. This is a no-op and is provided only for backwards
compatibility.
=item binc()
$x->binc(); # increment x by 1
=item bdec()
$x->bdec(); # decrement x by 1
=item badd()
$x->badd($y); # addition (add $y to $x)
=item bsub()
$x->bsub($y); # subtraction (subtract $y from $x)
=item bmul()
$x->bmul($y); # multiplication (multiply $x by $y)
=item bdiv()
$x->bdiv($y); # set $x to quotient
($q, $r) = $x->bdiv($y); # also return remainder
The behaviour of L and L is based on Perl's C<%> operator,
which is the remainder after performing floored division.
Because of this, L and L are aliases for L and
L, respectively.
=item bmod()
$x->bmod($y); # modulus (x % y)
This is an alias for L.
=item bfdiv()
$x->bfdiv($y); # return quotient
($q, $r) = $x->bfdiv($y); # return quotient and remainder
Divides $x by $y by doing floored division (F-division), where the quotient is
the floored (rounded towards negative infinity) quotient of the two operands.
In list context, returns the quotient and the remainder. In scalar context,
only the quotient is returned.
$q = floor($x / $y) # quotient
$r = $x - $q * $y # remainder
With F-division, the remainder is either zero or has the same sign as the
divisor.
7 / 4 => ( 1, 3)
-7 / 4 => (-2, 1)
-7 / -4 => ( 1, -3)
7 / -4 => (-2, -1)
The behavior of the overloaded operator % agrees with the behavior of Perl's
built-in % operator (as documented in the perlop manpage), and the equation
$x == ($x / $y) * $y + ($x % $y)
holds true for any finite $x and finite, non-zero $y.
Perl's "use integer" might change the behaviour of % and / for scalars. This is
because under 'use integer' Perl does what the underlying C library thinks is
right, and this varies. However, "use integer" does not change the way things
are done with Math::BigInt objects.
=item bfmod()
$x->bfmod($y); # floored modulus (x % y)
Returns $x modulo $y, i.e., the remainder after floored division (F-division).
This method is like Perl's % operator. See L.
=item btdiv()
$x->btdiv($y); # divide, set $x to quotient
Divides $x by $y by doing truncated division (T-division), where quotient is
the truncated (rouneded towards zero) quotient of the two operands. In list
context, returns the quotient and the remainder. The remainder is either zero
or has the same sign as the first operand. In scalar context, only the quotient
is returned.
=item btmod()
$x->btmod($y); # modulus
Returns the remainer after truncated division (T-division). See L.
=item binv()
$x->binv();
Invert the value of $x, i.e., compute 1/$x.
=item bsqrt()
$x->bsqrt(); # calculate square root
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 bpow()
$x->bpow($y); # power of arguments (x ** y)
Returns $x raised to the power of $y. The first two modifies $x, the last one
doesn't:
print $x->bpow($i),"\n"; # modifies $x
print $x **= $i,"\n"; # ditto
print $x ** $i,"\n"; # leaves $x alone
The form C<$x **= $y> is faster than C<$x = $x ** $y;>, though.
=item broot()
$x->broot($N);
Calculates the $N'th root of C<$x>.
=item bmuladd()
$x->bmuladd($y,$z);
Multiply $x by $y, and then add $z to the result,
This method was added in v1.88 of Math::BigInt.
=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 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 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 bilog2()
Base 2 logarithm rounded down towards the nearest integer.
$x->bilog2(); # int(log2(x)) = int(log(x)/log(2))
In list context a second argument is returned. This is 1 if the result is
exact, i.e., the input is an exact power of 2, and 0 otherwise.
=item bilog10()
Base 10 logarithm rounded down towards the nearest integer.
$x->bilog10(); # int(log10(x)) = int(log(x)/log(10))
In list context a second argument is returned. This is 1 if the result is
exact, i.e., the input is an exact power of 10, and 0 otherwise.
=item bclog2()
Base 2 logarithm rounded up towards the nearest integer.
$x->bclog2(); # ceil(log2(x)) = ceil(log(x)/log(2))
In list context a second argument is returned. This is 1 if the result is
exact, i.e., the input is an exact power of 2, and 0 otherwise.
=item bclog10()
Base 10 logarithm rounded up towards the nearest integer.
$x->bclog10(); # ceil(log10(x)) = ceil(log(x)/log(10))
In list context a second argument is returned. This is 1 if the result is
exact, i.e., the input is an exact power of 10, and 0 otherwise.
=item bnok()
Combinations.
$n->bnok($k); # binomial coefficient n over k
Calculates the binomial coefficient n over k, also called the "choose"
function, which is the number of ways to choose a sample of k elements from a
set of n distinct objects where order does not matter and replacements are not
allowed. The result is equivalent to
/ n \ n!
C(n, k) = | | = -------- where 0 <= k <= 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 bperm()
Permutations
$n->bperm($k);
Calculates the number of ways to choose a sample of k elements from a set of n
distinct objects where order does matter and replacements are not allowed.
n!
P(n, k) = ------ where 0 <= k <= n
(n-k)!
=item bhyperop()
=item hyperop()
$a -> bhyperop($n, $b); # modifies $a
$x = $a -> hyperop($n, $b); # does not modify $a
H_n(a, b) = a[n]b is the Ith hyperoperator,
n = 0 : succession (b + 1)
n = 1 : addition (a + b)
n = 2 : multiplication (a * b)
n = 3 : exponentiation (a ** b)
n = 4 : tetration (a ** a ** ... ** a) (b occurrences of a)
...
/ b+1 if n = 0
| a if n = 1 and b = 0
H_n(a, b) = a[n]b = | 0 if n = 2 and b = 0
| 1 if n >= 3 and b = 0
\ H_(n-1)(a, H_n(a, b-1)) otherwise
Note that the result can be a very large number, even for small operands. Also
note that the backend library C silently returns the
incorrect result when the numbers are larger than it can handle. It is better
to use C or C; they throw an error if
they can't handle the number.
See also L, L.
=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.
The L method is equivalent to the L method with an
offset of two. The following two give the same result:
$x -> buparrow($n, $b);
$x -> bhyperop($n + 2, $b);
See also L,
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 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 blsft()
Left shift.
$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));
=item brsft()
Right shift.
$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));
=back
=head2 Bitwise methods
For all bitwise methods, the operands are truncated to integers, i.e., rounded
towards zero, if necessary, before the method is applied. The bitwise methods
never upgrade, and they always return an integer.
=over
=item bblsft()
Bitwise left shift. This is equivalent to Perl's CE> operator.
$x -> bblsft($n); # left shift $n places in base 2
If C<$n> is negative, the shifting is done in the opposite direction, so these
two are equivalent for all C<$x> and C<$n>
$y = $x -> bblsft($n);
$y = $x -> bbrsft(-$n);
and also equivalent to
$y = $x -> bmul(ref($x) -> new(2) -> bpow($n)); # if $n > 0
$y = $x -> bdiv(ref($x) -> new(2) -> bpow($n)); # if $n < 0
=item bbrsft()
Bitwise right shift. This is equivalent to Perl's CE> operator.
$x -> bbrsft($n); # right shift $n places in base 2
If C<$n> is negative, the shifting is done in the opposite direction, so these
two are equivalent for all C<$x> and C<$n>
$y = $x -> bbrsft($n);
$y = $x -> bblsft(-$n);
and also equivalent to
$y = $x -> bdiv(ref($x) -> new(2) -> bpow($n)); # if $n > 0
$y = $x -> bmul(ref($x) -> new(2) -> bpow(-$n)); # if $n < 0
=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), which is the largest positive
integer that divides each of the operands.
=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 bdigitsum()
$x->bdigitsum();
Computes the sum of the base 10 digits and assigns the result to the invocand.
=item digitsum()
$x->digitsum();
Computes the sum of the base 10 digits and returns it.
=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 L 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 L corresponds to the
output from L.
In Math::BigInt, this method is identical to L.
=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 L corresponds to the output from
L. 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
L corresponds to the output from L. 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 L corresponds to the output from L.
=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, L 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, L 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 L.
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 L.
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 L.
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 L.
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 bfstr()
Returns a string representing the number using fractional notation. The output
corresponds to the output from L.
12.345 is returned as "2469/200"
123.45 is returned as "2469/20"
1234.5 is returned as "2469/2"
12345 is returned as "12345"
123450 is returned as "123450"
=item to_hex()
$x->to_hex();
Returns a hexadecimal string representation of the number. See also
L.
=item to_oct()
$x->to_oct();
Returns an octal string representation of the number. See also L.
=item to_bin()
$x->to_bin();
Returns a binary string representation of the number. See also L.
=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 L.
=item to_ieee754()
See L.
=item to_fp80()
See L.
=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 "|--"
If the collation sequence are the bytes from "\x00" to "\xff", and the base is
256, then L returns the same output as L. In the
following example, $x and $y are identical:
$cs = join "", map chr, 0 .. 255; # collation sequence
$x = Math::BigInt -> to_base("1230129310", 256, $cs)
$y = Math::BigInt -> to_bytes("1230129310");
See L for information and examples.
=item to_base_num()
Converts the given number to the given base. This method is equivalent to
L, but returns numbers in an array rather than characters in a
string. In the output, the first element is the most significant.
$x = Math::BigInt->new(13); # decimal 13 is binary 1101
$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, L, but with a "0x" prefix.
=item as_oct()
$x->as_oct();
As, L, but with a "0" prefix.
=item as_bin()
$x->as_bin();
As, L, but with a "0b" prefix.
=item as_bytes()
This is an alias for L.
=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), R (rounding mode), and F (fallback) are be used.
=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 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 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
=head2 Fallback F
When neither A nor P are defined, the fallback accuracy is used when computing
values that would potentially give an infinite number of digits, e.g.,
division, roots, logarithms, trigonometric functions etc.
=head2 More details on rounding
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
* A: undef
* P: undef
* R: 'even'
* F: 40
=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 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 values that are not numbers, e.g., the
result of 0/0. '+inf' and '-inf' represen positive and negative infinity,
respectively. For example 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