# -*- coding: utf-8-unix -*-
package Math::BigInt;
#
# "Mike had an infinite amount to do and a negative amount of time in which
# to do it." - Before and After
#
# The following hash values are used:
# value: unsigned int with actual value (as a Math::BigInt::Calc or similar)
# sign : +, -, NaN, +inf, -inf
# _a : accuracy
# _p : precision
# Remember not to take shortcuts ala $xs = $x->{value}; $LIB->foo($xs); since
# underlying lib might change the reference!
use 5.006001;
use strict;
use warnings;
use Carp qw;
use Scalar::Util qw;
our $VERSION = '1.999830';
$VERSION =~ tr/_//d;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(objectify bgcd blcm);
# Inside overload, the first arg is always an object. If the original code had
# it reversed (like $x = 2 * $y), then the third parameter is true.
# In some cases (like add, $x = $x + 2 is the same as $x = 2 + $x) this makes
# no difference, but in some cases it does.
# For overloaded ops with only one argument we simple use $_[0]->copy() to
# preserve the argument.
# Thus inheritance of overload operators becomes possible and transparent for
# our subclasses without the need to repeat the entire overload section there.
use overload
# overload key: with_assign
'+' => sub { $_[0] -> copy() -> badd($_[1]); },
'-' => sub { my $c = $_[0] -> copy();
$_[2] ? $c -> bneg() -> badd($_[1])
: $c -> bsub($_[1]); },
'*' => sub { $_[0] -> copy() -> bmul($_[1]); },
'/' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bdiv($_[0])
: $_[0] -> copy() -> bdiv($_[1]); },
'%' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bmod($_[0])
: $_[0] -> copy() -> bmod($_[1]); },
'**' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bpow($_[0])
: $_[0] -> copy() -> bpow($_[1]); },
' sub { $_[2] ? ref($_[0]) -> new($_[1]) -> blsft($_[0])
: $_[0] -> copy() -> blsft($_[1]); },
'>>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> brsft($_[0])
: $_[0] -> copy() -> brsft($_[1]); },
# overload key: assign
'+=' => sub { $_[0] -> badd($_[1]); },
'-=' => sub { $_[0] -> bsub($_[1]); },
'*=' => sub { $_[0] -> bmul($_[1]); },
'/=' => sub { scalar $_[0] -> bdiv($_[1]); },
'%=' => sub { $_[0] -> bmod($_[1]); },
'**=' => sub { $_[0] -> bpow($_[1]); },
' sub { $_[0] -> blsft($_[1]); },
'>>=' => sub { $_[0] -> brsft($_[1]); },
# 'x=' => sub { },
# '.=' => sub { },
# overload key: num_comparison
' sub { $_[2] ? ref($_[0]) -> new($_[1]) -> blt($_[0])
: $_[0] -> blt($_[1]); },
' sub { $_[2] ? ref($_[0]) -> new($_[1]) -> ble($_[0])
: $_[0] -> ble($_[1]); },
'>' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bgt($_[0])
: $_[0] -> bgt($_[1]); },
'>=' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bge($_[0])
: $_[0] -> bge($_[1]); },
'==' => sub { $_[0] -> beq($_[1]); },
'!=' => sub { $_[0] -> bne($_[1]); },
# overload key: 3way_comparison
'' => sub { my $cmp = $_[0] -> bcmp($_[1]);
defined($cmp) && $_[2] ? -$cmp : $cmp; },
'cmp' => sub { $_[2] ? "$_[1]" cmp $_[0] -> bstr()
: $_[0] -> bstr() cmp "$_[1]"; },
# overload key: str_comparison
# 'lt' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrlt($_[0])
# : $_[0] -> bstrlt($_[1]); },
#
# 'le' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrle($_[0])
# : $_[0] -> bstrle($_[1]); },
#
# 'gt' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrgt($_[0])
# : $_[0] -> bstrgt($_[1]); },
#
# 'ge' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bstrge($_[0])
# : $_[0] -> bstrge($_[1]); },
#
# 'eq' => sub { $_[0] -> bstreq($_[1]); },
#
# 'ne' => sub { $_[0] -> bstrne($_[1]); },
# overload key: binary
'&' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> band($_[0])
: $_[0] -> copy() -> band($_[1]); },
'&=' => sub { $_[0] -> band($_[1]); },
'|' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bior($_[0])
: $_[0] -> copy() -> bior($_[1]); },
'|=' => sub { $_[0] -> bior($_[1]); },
'^' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> bxor($_[0])
: $_[0] -> copy() -> bxor($_[1]); },
'^=' => sub { $_[0] -> bxor($_[1]); },
# '&.' => sub { },
# '&.=' => sub { },
# '|.' => sub { },
# '|.=' => sub { },
# '^.' => sub { },
# '^.=' => sub { },
# overload key: unary
'neg' => sub { $_[0] -> copy() -> bneg(); },
# '!' => sub { },
'~' => sub { $_[0] -> copy() -> bnot(); },
# '~.' => sub { },
# overload key: mutators
'++' => sub { $_[0] -> binc() },
'--' => sub { $_[0] -> bdec() },
# overload key: func
'atan2' => sub { $_[2] ? ref($_[0]) -> new($_[1]) -> batan2($_[0])
: $_[0] -> copy() -> batan2($_[1]); },
'cos' => sub { $_[0] -> copy() -> bcos(); },
'sin' => sub { $_[0] -> copy() -> bsin(); },
'exp' => sub { $_[0] -> copy() -> bexp($_[1]); },
'abs' => sub { $_[0] -> copy() -> babs(); },
'log' => sub { $_[0] -> copy() -> blog(); },
'sqrt' => sub { $_[0] -> copy() -> bsqrt(); },
'int' => sub { $_[0] -> copy() -> bint(); },
# overload key: conversion
'bool' => sub { $_[0] -> is_zero() ? '' : 1; },
'""' => sub { $_[0] -> bstr(); },
'0+' => sub { $_[0] -> numify(); },
'=' => sub { $_[0] -> copy(); },
;
##############################################################################
# global constants, flags and accessory
# These vars are public, but their direct usage is not recommended, use the
# accessor methods instead
our $round_mode = 'even'; # one of 'even', 'odd', '+inf', '-inf', 'zero', 'trunc' or 'common'
our $accuracy = undef;
our $precision = undef;
our $div_scale = 40;
our $upgrade = undef; # default is no upgrade
our $downgrade = undef; # default is no downgrade
# These are internally, and not to be used from the outside at all
our $_trap_nan = 0; # are NaNs ok? set w/ config()
our $_trap_inf = 0; # are infs ok? set w/ config()
my $nan = 'NaN'; # constants for easier life
# Module to do the low level math.
my $DEFAULT_LIB = 'Math::BigInt::Calc';
my $LIB;
# Has import() been called yet? Needed to make "require" work.
my $IMPORT = 0;
##############################################################################
# the old code had $rnd_mode, so we need to support it, too
our $rnd_mode = 'even';
sub TIESCALAR {
my ($class) = @_;
bless \$round_mode, $class;
}
sub FETCH {
return $round_mode;
}
sub STORE {
$rnd_mode = $_[0]->round_mode($_[1]);
}
BEGIN {
# tie to enable $rnd_mode to work transparently
tie $rnd_mode, 'Math::BigInt';
# set up some handy alias names
*as_int = \&as_number;
*is_pos = \&is_positive;
*is_neg = \&is_negative;
}
###############################################################################
# Configuration methods
###############################################################################
sub round_mode {
my $self = shift;
my $class = ref($self) || $self || __PACKAGE__;
if (@_) { # setter
my $m = shift;
croak("The value for 'round_mode' must be defined")
unless defined $m;
croak("Unknown round mode '$m'")
unless $m =~ /^(even|odd|\+inf|\-inf|zero|trunc|common)$/;
no strict 'refs';
${"${class}::round_mode"} = $m;
}
else { # getter
no strict 'refs';
my $m = ${"${class}::round_mode"};
defined($m) ? $m : $round_mode;
}
}
sub upgrade {
no strict 'refs';
# make Class->upgrade() work
my $self = shift;
my $class = ref($self) || $self || __PACKAGE__;
# need to set new value?
if (@_ > 0) {
return ${"${class}::upgrade"} = $_[0];
}
${"${class}::upgrade"};
}
sub downgrade {
no strict 'refs';
# make Class->downgrade() work
my $self = shift;
my $class = ref($self) || $self || __PACKAGE__;
# need to set new value?
if (@_ > 0) {
return ${"${class}::downgrade"} = $_[0];
}
${"${class}::downgrade"};
}
sub div_scale {
my $self = shift;
my $class = ref($self) || $self || __PACKAGE__;
if (@_) { # setter
my $ds = shift;
croak("The value for 'div_scale' must be defined") unless defined $ds;
croak("The value for 'div_scale' must be positive") unless $ds > 0;
$ds = $ds -> numify() if defined(blessed($ds));
no strict 'refs';
${"${class}::div_scale"} = $ds;
}
else { # getter
no strict 'refs';
my $ds = ${"${class}::div_scale"};
defined($ds) ? $ds : $div_scale;
}
}
sub accuracy {
# $x->accuracy($a); ref($x) $a
# $x->accuracy(); ref($x)
# Class->accuracy(); class
# Class->accuracy($a); class $a
my $x = shift;
my $class = ref($x) || $x || __PACKAGE__;
no strict 'refs';
if (@_ > 0) {
my $a = shift;
if (defined $a) {
$a = $a->numify() if ref($a) && $a->can('numify');
# also croak on non-numerical
if (!$a || $a bround($a) if $a; # not for undef, 0
$x->{_a} = $a; # set/overwrite, even if not rounded
delete $x->{_p}; # clear P
# Why return class variable here? Fixme!
$a = ${"${class}::accuracy"} unless defined $a; # proper return value
} else {
# Set class variable.
${"${class}::accuracy"} = $a; # set global A
${"${class}::precision"} = undef; # clear global P
}
return $a; # shortcut
}
# Return instance variable.
return $x->{_a} if ref($x) && (defined $x->{_a} || defined $x->{_p});
# Return class variable.
return ${"${class}::accuracy"};
}
sub precision {
# $x->precision($p); ref($x) $p
# $x->precision(); ref($x)
# Class->precision(); class
# Class->precision($p); class $p
my $x = shift;
my $class = ref($x) || $x || __PACKAGE__;
no strict 'refs';
if (@_ > 0) {
my $p = shift;
if (defined $p) {
$p = $p->numify() if ref($p) && $p->can('numify');
if ($p != int $p) {
croak('Argument to precision must be an integer');
}
}
if (ref($x)) {
# Set instance variable.
$x->bfround($p) if $p; # not for undef, 0
$x->{_p} = $p; # set/overwrite, even if not rounded
delete $x->{_a}; # clear A
# Why return class variable here? Fixme!
$p = ${"${class}::precision"} unless defined $p; # proper return value
} else {
# Set class variable.
${"${class}::precision"} = $p; # set global P
${"${class}::accuracy"} = undef; # clear global A
}
return $p; # shortcut
}
# Return instance variable.
return $x->{_p} if ref($x) && (defined $x->{_a} || defined $x->{_p});
# Return class variable.
return ${"${class}::precision"};
}
sub config {
# return (or set) configuration data.
my $class = shift || __PACKAGE__;
no strict 'refs';
if (@_ > 1 || (@_ == 1 && (ref($_[0]) eq 'HASH'))) {
# try to set given options as arguments from hash
my $args = $_[0];
if (ref($args) ne 'HASH') {
$args = { @_ };
}
# these values can be "set"
my $set_args = {};
foreach my $key (qw/
accuracy precision
round_mode div_scale
upgrade downgrade
trap_inf trap_nan
/)
{
$set_args->{$key} = $args->{$key} if exists $args->{$key};
delete $args->{$key};
}
if (keys %$args > 0) {
croak("Illegal key(s) '", join("', '", keys %$args),
"' passed to $class\->config()");
}
foreach my $key (keys %$set_args) {
if ($key =~ /^trap_(inf|nan)\z/) {
${"${class}::_trap_$1"} = ($set_args->{"trap_$1"} ? 1 : 0);
next;
}
# use a call instead of just setting the $variable to check argument
$class->$key($set_args->{$key});
}
}
# now return actual configuration
my $cfg = {
lib => $LIB,
lib_version => ${"${LIB}::VERSION"},
class => $class,
trap_nan => ${"${class}::_trap_nan"},
trap_inf => ${"${class}::_trap_inf"},
version => ${"${class}::VERSION"},
};
foreach my $key (qw/
accuracy precision
round_mode div_scale
upgrade downgrade
/)
{
$cfg->{$key} = ${"${class}::$key"};
}
if (@_ == 1 && (ref($_[0]) ne 'HASH')) {
# calls of the style config('lib') return just this value
return $cfg->{$_[0]};
}
$cfg;
}
sub _scale_a {
# select accuracy parameter based on precedence,
# used by bround() and bfround(), may return undef for scale (means no op)
my ($x, $scale, $mode) = @_;
$scale = $x->{_a} unless defined $scale;
no strict 'refs';
my $class = ref($x);
$scale = ${ $class . '::accuracy' } unless defined $scale;
$mode = ${ $class . '::round_mode' } unless defined $mode;
if (defined $scale) {
$scale = $scale->can('numify') ? $scale->numify()
: "$scale" if ref($scale);
$scale = int($scale);
}
($scale, $mode);
}
sub _scale_p {
# select precision parameter based on precedence,
# used by bround() and bfround(), may return undef for scale (means no op)
my ($x, $scale, $mode) = @_;
$scale = $x->{_p} unless defined $scale;
no strict 'refs';
my $class = ref($x);
$scale = ${ $class . '::precision' } unless defined $scale;
$mode = ${ $class . '::round_mode' } unless defined $mode;
if (defined $scale) {
$scale = $scale->can('numify') ? $scale->numify()
: "$scale" if ref($scale);
$scale = int($scale);
}
($scale, $mode);
}
###############################################################################
# Constructor methods
###############################################################################
sub new {
# Create a new Math::BigInt object from a string or another Math::BigInt
# object. See hash keys documented at top.
# The argument could be an object, so avoid ||, && etc. on it. This would
# cause costly overloaded code to be called. The only allowed ops are ref()
# and defined.
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Make "require" work.
$class -> import() if $IMPORT == 0;
# Although this use has been discouraged for more than 10 years, people
# apparently still use it, so we still support it.
return $class -> bzero() unless @_;
my ($wanted, @r) = @_;
if (!defined($wanted)) {
#if (warnings::enabled("uninitialized")) {
# warnings::warn("uninitialized",
# "Use of uninitialized value in new()");
#}
return $class -> bzero(@r);
}
if (!ref($wanted) && $wanted eq "") {
#if (warnings::enabled("numeric")) {
# warnings::warn("numeric",
# q|Argument "" isn't numeric in new()|);
#}
#return $class -> bzero(@r);
return $class -> bnan(@r);
}
# Initialize a new object.
$self = bless {}, $class;
# Math::BigInt or subclass
if (defined(blessed($wanted)) && $wanted -> isa($class)) {
# We don't copy the accuracy and precision, because a new object should
# get them from the global configuration.
$self -> {sign} = $wanted -> {sign};
$self -> {value} = $LIB -> _copy($wanted -> {value});
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
# Shortcut for non-zero scalar integers with no non-zero exponent.
if ($wanted =~ / ^
([+-]?) # optional sign
([1-9][0-9]*) # non-zero significand
(\.0*)? # ... with optional zero fraction
([Ee][+-]?0+)? # optional zero exponent
\z
/x)
{
my $sgn = $1;
my $abs = $2;
$self->{sign} = $sgn || '+';
$self->{value} = $LIB->_new($abs);
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
# Handle Infs.
if ($wanted =~ /^\s*([+-]?)inf(inity)?\s*\z/i) {
my $sgn = $1 || '+';
$self = $class -> binf($sgn);
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
# Handle explicit NaNs (not the ones returned due to invalid input).
if ($wanted =~ /^\s*([+-]?)nan\s*\z/i) {
$self = $class -> bnan();
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
my @parts;
if (
# Handle hexadecimal numbers. We auto-detect hexadecimal numbers if they
# have a "0x", "0X", "x", or "X" prefix, cf. CORE::oct().
$wanted =~ /^\s*[+-]?0?[Xx]/ and
@parts = $class -> _hex_str_to_lib_parts($wanted)
or
# Handle octal numbers. We auto-detect octal numbers if they have a
# "0o", "0O", "o", "O" prefix, cf. CORE::oct().
$wanted =~ /^\s*[+-]?0?[Oo]/ and
@parts = $class -> _oct_str_to_lib_parts($wanted)
or
# Handle binary numbers. We auto-detect binary numbers if they have a
# "0b", "0B", "b", or "B" prefix, cf. CORE::oct().
$wanted =~ /^\s*[+-]?0?[Bb]/ and
@parts = $class -> _bin_str_to_lib_parts($wanted)
or
# At this point, what is left are decimal numbers that aren't handled
# above and octal floating point numbers that don't have any of the
# "0o", "0O", "o", or "O" prefixes. First see if it is a decimal number.
@parts = $class -> _dec_str_to_lib_parts($wanted)
or
# See if it is an octal floating point number. The extra check is
# included because _oct_str_to_lib_parts() accepts octal numbers that
# don't have a prefix (this is needed to make it work with, e.g.,
# from_oct() that don't require a prefix). However, Perl requires a
# prefix for octal floating point literals. For example, "1p+0" is not
# valid, but "01p+0" and "0__1p+0" are.
$wanted =~ /^\s*[+-]?0_*\d/ and
@parts = $class -> _oct_str_to_lib_parts($wanted))
{
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+') {
$self -> {sign} = $parts[0];
$self -> {value} = $LIB -> _lsft($parts[1], $parts[3], 10);
$self->round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
# If we get here, the value is a valid number, but it is not an integer.
return $upgrade -> new($wanted, @r) if defined $upgrade;
return $class -> bnan();
}
# If we get here, the value is neither a valid decimal, binary, octal, or
# hexadecimal number. It is not explicit an Inf or a NaN either.
return $class -> bnan();
}
# Create a Math::BigInt from a decimal string. This is an equivalent to
# from_hex(), from_oct(), and from_bin(). It is like new() except that it does
# not accept anything but a string representing a finite decimal number.
sub from_dec {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_dec');
my $str = shift;
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
if (my @parts = $class -> _dec_str_to_lib_parts($str)) {
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+') {
$self -> {sign} = $parts[0];
$self -> {value} = $LIB -> _lsft($parts[1], $parts[3], 10);
return $self -> round(@r);
}
return $upgrade -> new($str, @r) if defined $upgrade;
}
return $self -> bnan(@r);
}
# Create a Math::BigInt from a hexadecimal string.
sub from_hex {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_hex');
my $str = shift;
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
if (my @parts = $class -> _hex_str_to_lib_parts($str)) {
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+') {
$self -> {sign} = $parts[0];
$self -> {value} = $LIB -> _lsft($parts[1], $parts[3], 10);
return $self -> round(@r);
}
return $upgrade -> new($str, @r) if defined $upgrade;
}
return $self -> bnan(@r);
}
# Create a Math::BigInt from an octal string.
sub from_oct {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_oct');
my $str = shift;
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
if (my @parts = $class -> _oct_str_to_lib_parts($str)) {
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+') {
$self -> {sign} = $parts[0];
$self -> {value} = $LIB -> _lsft($parts[1], $parts[3], 10);
return $self -> round(@r);
}
return $upgrade -> new($str, @r) if defined $upgrade;
}
return $self -> bnan(@r);
}
# Create a Math::BigInt from a binary string.
sub from_bin {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_bin');
my $str = shift;
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
if (my @parts = $class -> _bin_str_to_lib_parts($str)) {
# The value is an integer iff the exponent is non-negative.
if ($parts[2] eq '+') {
$self -> {sign} = $parts[0];
$self -> {value} = $LIB -> _lsft($parts[1], $parts[3], 10);
return $self -> round(@r);
}
return $upgrade -> new($str, @r) if defined $upgrade;
}
return $self -> bnan(@r);
}
# Create a Math::BigInt from a byte string.
sub from_bytes {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_bytes');
croak("from_bytes() requires a newer version of the $LIB library.")
unless $LIB->can('_from_bytes');
my $str = shift;
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
$self -> {sign} = '+';
$self -> {value} = $LIB -> _from_bytes($str);
return $self -> round(@r);
}
sub from_base {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_base');
my $str = shift;
my $base = shift;
$base = $class->new($base) unless ref($base);
croak("the base must be a finite integer >= 2")
if $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.
if (! @_) {
return $self -> from_bin($str) if $base == 2;
return $self -> from_oct($str) if $base == 8;
return $self -> from_hex($str) if $base == 16;
if ($base == 10) {
my $tmp = $class -> new($str);
$self -> {value} = $tmp -> {value};
$self -> {sign} = '+';
}
}
croak("from_base() requires a newer version of the $LIB library.")
unless $LIB->can('_from_base');
$self -> {sign} = '+';
$self -> {value}
= $LIB->_from_base($str, $base -> {value}, @_ ? shift() : ());
return $self;
}
sub from_base_num {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('from_base_num');
# Make sure we have an array of non-negative, finite, numerical objects.
my $nums = shift;
$nums = [ @$nums ]; # create new reference
for my $i (0 .. $#$nums) {
# Make sure we have an object.
$nums -> [$i] = $class -> new($nums -> [$i])
unless ref($nums -> [$i]) && $nums -> [$i] -> isa($class);
# Make sure we have a finite, non-negative integer.
croak "the elements must be finite non-negative integers"
if $nums -> [$i] -> is_neg() || ! $nums -> [$i] -> is_int();
}
my $base = shift;
$base = $class -> new($base) unless ref($base) && $base -> isa($class);
my @r = @_;
# If called as a class method, initialize a new object.
$self = $class -> bzero() unless $selfref;
croak("from_base_num() requires a newer version of the $LIB library.")
unless $LIB->can('_from_base_num');
$self -> {sign} = '+';
$self -> {value} = $LIB -> _from_base_num([ map { $_ -> {value} } @$nums ],
$base -> {value});
return $self -> round(@r);
}
sub bzero {
# create/assign '+0'
if (@_ == 0) {
#carp("Using bzero() as a function is deprecated;",
# " use bzero() as a method instead");
unshift @_, __PACKAGE__;
}
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
$self->import() if $IMPORT == 0; # make require work
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('bzero');
$self = bless {}, $class unless $selfref;
$self->{sign} = '+';
$self->{value} = $LIB->_zero();
# If rounding parameters are given as arguments, use them. If no rounding
# parameters are given, and if called as a class method initialize the new
# instance with the class variables.
if (@_) {
croak "can't specify both accuracy and precision"
if @_ >= 2 && defined $_[0] && defined $_[1];
$self->{_a} = $_[0];
$self->{_p} = $_[1];
} else {
unless($selfref) {
$self->{_a} = $class -> accuracy();
$self->{_p} = $class -> precision();
}
}
return $self;
}
sub bone {
# Create or assign '+1' (or -1 if given sign '-').
if (@_ == 0 || (defined($_[0]) && ($_[0] eq '+' || $_[0] eq '-'))) {
#carp("Using bone() as a function is deprecated;",
# " use bone() as a method instead");
unshift @_, __PACKAGE__;
}
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
$self->import() if $IMPORT == 0; # make require work
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('bone');
my $sign = '+'; # default
if (@_) {
$sign = shift;
$sign = $sign =~ /^\s*-/ ? "-" : "+";
}
$self = bless {}, $class unless $selfref;
$self->{sign} = $sign;
$self->{value} = $LIB->_one();
# If rounding parameters are given as arguments, use them. If no rounding
# parameters are given, and if called as a class method initialize the new
# instance with the class variables.
if (@_) {
croak "can't specify both accuracy and precision"
if @_ >= 2 && defined $_[0] && defined $_[1];
$self->{_a} = $_[0];
$self->{_p} = $_[1];
} else {
unless($selfref) {
$self->{_a} = $class -> accuracy();
$self->{_p} = $class -> precision();
}
}
return $self;
}
sub binf {
# create/assign a '+inf' or '-inf'
if (@_ == 0 || (defined($_[0]) && !ref($_[0]) &&
$_[0] =~ /^\s*[+-](inf(inity)?)?\s*$/))
{
#carp("Using binf() as a function is deprecated;",
# " use binf() as a method instead");
unshift @_, __PACKAGE__;
}
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
{
no strict 'refs';
if (${"${class}::_trap_inf"}) {
croak("Tried to create +-inf in $class->binf()");
}
}
$self->import() if $IMPORT == 0; # make require work
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('binf');
my $sign = shift;
$sign = defined $sign && $sign =~ /^\s*-/ ? "-" : "+";
$self = bless {}, $class unless $selfref;
$self -> {sign} = $sign . 'inf';
$self -> {value} = $LIB -> _zero();
# If rounding parameters are given as arguments, use them. If no rounding
# parameters are given, and if called as a class method initialize the new
# instance with the class variables.
if (@_) {
croak "can't specify both accuracy and precision"
if @_ >= 2 && defined $_[0] && defined $_[1];
$self->{_a} = $_[0];
$self->{_p} = $_[1];
} else {
unless($selfref) {
$self->{_a} = $class -> accuracy();
$self->{_p} = $class -> precision();
}
}
return $self;
}
sub bnan {
# create/assign a 'NaN'
if (@_ == 0) {
#carp("Using bnan() as a function is deprecated;",
# " use bnan() as a method instead");
unshift @_, __PACKAGE__;
}
my $self = shift;
my $selfref = ref($self);
my $class = $selfref || $self;
{
no strict 'refs';
if (${"${class}::_trap_nan"}) {
croak("Tried to create NaN in $class->bnan()");
}
}
$self->import() if $IMPORT == 0; # make require work
# Don't modify constant (read-only) objects.
return if $selfref && $self->modify('bnan');
$self = bless {}, $class unless $selfref;
$self -> {sign} = $nan;
$self -> {value} = $LIB -> _zero();
# If rounding parameters are given as arguments, use them. If no rounding
# parameters are given, and if called as a class method initialize the new
# instance with the class variables.
if (@_) {
croak "can't specify both accuracy and precision"
if @_ >= 2 && defined $_[0] && defined $_[1];
$self->{_a} = $_[0];
$self->{_p} = $_[1];
} else {
unless($selfref) {
$self->{_a} = $class -> accuracy();
$self->{_p} = $class -> precision();
}
}
return $self;
}
sub bpi {
# Called as Argument list
# --------- -------------
# Math::BigInt->bpi() ("Math::BigInt")
# Math::BigInt->bpi(10) ("Math::BigInt", 10)
# $x->bpi() ($x)
# $x->bpi(10) ($x, 10)
# Math::BigInt::bpi() ()
# Math::BigInt::bpi(10) (10)
#
# In ambiguous cases, we favour the OO-style, so the following case
#
# $n = Math::BigInt->new("10");
# $x = Math::BigInt->bpi($n);
#
# which gives an argument list with the single element $n, is resolved as
#
# $n->bpi();
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
my @r; # rounding paramters
# If bpi() is called as a function ...
#
# This cludge is necessary because we still support bpi() as a function. If
# bpi() is called with either no argument or one argument, and that one
# argument is either undefined or a scalar that looks like a number, then
# we assume bpi() is called as a function.
if (@_ == 0 &&
(defined($self) && !ref($self) && $self =~ /^\s*[+-]?\d/)
||
!defined($self))
{
$r[0] = $self;
$class = __PACKAGE__;
$self = bless {}, $class;
}
# ... or if bpi() is called as a method ...
else {
@r = @_;
if ($selfref) { # bpi() called as instance method
return $self if $self -> modify('bpi');
} else { # bpi() called as class method
$self = bless {}, $class;
}
}
return $upgrade -> bpi(@r) if defined $upgrade;
# hard-wired to "3"
$self -> {sign} = '+';
$self -> {value} = $LIB -> _new("3");
$self -> round(@r) unless @r >= 2 && !defined($r[0]) && !defined($r[1]);
return $self;
}
sub copy {
my $self = shift;
my $selfref = ref $self;
my $class = $selfref || $self;
# If called as a class method, the object to copy is the next argument.
$self = shift() unless $selfref;
my $copy = bless {}, $class;
$copy->{sign} = $self->{sign};
$copy->{value} = $LIB->_copy($self->{value});
$copy->{_a} = $self->{_a} if exists $self->{_a};
$copy->{_p} = $self->{_p} if exists $self->{_p};
return $copy;
}
sub as_number {
# An object might be asked to return itself as bigint on certain overloaded
# operations. This does exactly this, so that sub classes can simple inherit
# it or override with their own integer conversion routine.
$_[0]->copy();
}
###############################################################################
# Boolean methods
###############################################################################
sub is_zero {
# return true if arg (BINT or num_str) is zero (array '+', '0')
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
return 0 if $x->{sign} !~ /^\+$/; # -, NaN & +-inf aren't
$LIB->_is_zero($x->{value});
}
sub is_one {
# return true if arg (BINT or num_str) is +1, or -1 if sign is given
my ($class, $x, $sign) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
$sign = '+' if !defined $sign || $sign ne '-';
return 0 if $x->{sign} ne $sign; # -1 != +1, NaN, +-inf aren't either
$LIB->_is_one($x->{value});
}
sub is_finite {
my $x = shift;
return $x->{sign} eq '+' || $x->{sign} eq '-';
}
sub is_inf {
# return true if arg (BINT or num_str) is +-inf
my ($class, $x, $sign) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
if (defined $sign) {
$sign = '[+-]inf' if $sign eq ''; # +- doesn't matter, only that's inf
$sign = "[$1]inf" if $sign =~ /^([+-])(inf)?$/; # extract '+' or '-'
return $x->{sign} =~ /^$sign$/ ? 1 : 0;
}
$x->{sign} =~ /^[+-]inf$/ ? 1 : 0; # only +-inf is infinity
}
sub is_nan {
# return true if arg (BINT or num_str) is NaN
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
$x->{sign} eq $nan ? 1 : 0;
}
sub is_positive {
# return true when arg (BINT or num_str) is positive (> 0)
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
return 1 if $x->{sign} eq '+inf'; # +inf is positive
# 0+ is neither positive nor negative
($x->{sign} eq '+' && !$x->is_zero()) ? 1 : 0;
}
sub is_negative {
# return true when arg (BINT or num_str) is negative ({sign} =~ /^-/ ? 1 : 0; # -inf is negative, but NaN is not
}
sub is_non_negative {
# Return true if argument is non-negative (>= 0).
my ($class, $x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_);
return 1 if $x->{sign} =~ /^\+/;
return 1 if $x -> is_zero();
return 0;
}
sub is_non_positive {
# Return true if argument is non-positive ({sign} =~ /^\-/;
return 1 if $x -> is_zero();
return 0;
}
sub is_odd {
# return true when arg (BINT or num_str) is odd, false for even
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't
$LIB->_is_odd($x->{value});
}
sub is_even {
# return true when arg (BINT or num_str) is even, false for odd
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't
$LIB->_is_even($x->{value});
}
sub is_int {
# return true when arg (BINT or num_str) is an integer
# always true for Math::BigInt, but different for Math::BigFloat objects
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
$x->{sign} =~ /^[+-]$/ ? 1 : 0; # inf/-inf/NaN aren't
}
###############################################################################
# Comparison methods
###############################################################################
sub bcmp {
# Compares 2 values. Returns one of undef, 0. (suitable for sort)
# (BINT or num_str, BINT or num_str) return cond_code
# set up parameters
my ($class, $x, $y) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
return $upgrade->bcmp($x, $y) if defined $upgrade &&
((!$x->isa($class)) || (!$y->isa($class)));
if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) {
# handle +-inf and NaN
return if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
return 0 if $x->{sign} eq $y->{sign} && $x->{sign} =~ /^[+-]inf$/;
return +1 if $x->{sign} eq '+inf';
return -1 if $x->{sign} eq '-inf';
return -1 if $y->{sign} eq '+inf';
return +1;
}
# check sign for speed first
return 1 if $x->{sign} eq '+' && $y->{sign} eq '-'; # does also 0 -y
return -1 if $x->{sign} eq '-' && $y->{sign} eq '+'; # does also -x 0
# have same sign, so compare absolute values. Don't make tests for zero
# here because it's actually slower than testing in Calc (especially w/ Pari
# et al)
# post-normalized compare for internal use (honors signs)
if ($x->{sign} eq '+') {
# $x and $y both > 0
return $LIB->_acmp($x->{value}, $y->{value});
}
# $x && $y both _acmp($y->{value}, $x->{value}); # swapped acmp (lib returns 0, 1, -1)
}
sub bacmp {
# Compares 2 values, ignoring their signs.
# Returns one of undef, 0. (suitable for sort)
# (BINT, BINT) return cond_code
# set up parameters
my ($class, $x, $y) = ref($_[0]) && ref($_[0]) eq ref($_[1])
? (ref($_[0]), @_)
: objectify(2, @_);
return $upgrade->bacmp($x, $y) if defined $upgrade &&
((!$x->isa($class)) || (!$y->isa($class)));
if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) {
# handle +-inf and NaN
return if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/;
return 1 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} !~ /^[+-]inf$/;
return -1;
}
$LIB->_acmp($x->{value}, $y->{value}); # lib does only 0, 1, -1
}
sub beq {
my $self = shift;
my $selfref = ref $self;
croak 'beq() is an instance method, not a class method' unless $selfref;
croak 'Wrong number of arguments for beq()' unless @_ == 1;
my $cmp = $self -> bcmp(shift);
return defined($cmp) && ! $cmp;
}
sub bne {
my $self = shift;
my $selfref = ref $self;
croak 'bne() is an instance method, not a class method' unless $selfref;
croak 'Wrong number of arguments for bne()' unless @_ == 1;
my $cmp = $self -> bcmp(shift);
return defined($cmp) && ! $cmp ? '' : 1;
}
sub blt {
my $self = shift;
my $selfref = ref $self;
croak 'blt() is an instance method, not a class method' unless $selfref;
croak 'Wrong number of arguments for blt()' unless @_ == 1;
my $cmp = $self -> bcmp(shift);
return defined($cmp) && $cmp bcmp(shift);
return defined($cmp) && $cmp bcmp(shift);
return defined($cmp) && $cmp > 0;
}
sub bge {
my $self = shift;
my $selfref = ref $self;
croak 'bge() is an instance method, not a class method'
unless $selfref;
croak 'Wrong number of arguments for bge()' unless @_ == 1;
my $cmp = $self -> bcmp(shift);
return defined($cmp) && $cmp >= 0;
}
###############################################################################
# Arithmetic methods
###############################################################################
sub bneg {
# (BINT or num_str) return BINT
# negate number or make a negated number from string
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
return $x if $x->modify('bneg');
# for +0 do not negate (to have always normalized +0). Does nothing for 'NaN'
$x->{sign} =~ tr/+-/-+/ unless ($x->{sign} eq '+' && $LIB->_is_zero($x->{value}));
$x;
}
sub babs {
# (BINT or num_str) return BINT
# make number absolute, or return absolute BINT from string
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
return $x if $x->modify('babs');
# post-normalized abs for internal use (does nothing for NaN)
$x->{sign} =~ s/^-/+/;
$x;
}
sub bsgn {
# Signum function.
my $self = shift;
return $self if $self->modify('bsgn');
return $self -> bone("+") if $self -> is_pos();
return $self -> bone("-") if $self -> is_neg();
return $self; # zero or NaN
}
sub bnorm {
# (numstr or BINT) return BINT
# Normalize number -- no-op here
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
$x;
}
sub binc {
# increment arg by one
my ($class, $x, $a, $p, $r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('binc');
if ($x->{sign} eq '+') {
$x->{value} = $LIB->_inc($x->{value});
return $x->round($a, $p, $r);
} elsif ($x->{sign} eq '-') {
$x->{value} = $LIB->_dec($x->{value});
$x->{sign} = '+' if $LIB->_is_zero($x->{value}); # -1 +1 => -0 => +0
return $x->round($a, $p, $r);
}
# inf, nan handling etc
$x->badd($class->bone(), $a, $p, $r); # badd does round
}
sub bdec {
# decrement arg by one
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bdec');
if ($x->{sign} eq '-') {
# x already {value} = $LIB->_inc($x->{value});
} else {
return $x->badd($class->bone('-'), @r)
unless $x->{sign} eq '+'; # inf or NaN
# >= 0
if ($LIB->_is_zero($x->{value})) {
# == 0
$x->{value} = $LIB->_one();
$x->{sign} = '-'; # 0 => -1
} else {
# > 0
$x->{value} = $LIB->_dec($x->{value});
}
}
$x->round(@r);
}
#sub bstrcmp {
# my $self = shift;
# my $selfref = ref $self;
# my $class = $selfref || $self;
#
# croak 'bstrcmp() is an instance method, not a class method'
# unless $selfref;
# croak 'Wrong number of arguments for bstrcmp()' unless @_ == 1;
#
# return $self -> bstr() CORE::cmp shift;
#}
#
#sub bstreq {
# my $self = shift;
# my $selfref = ref $self;
# my $class = $selfref || $self;
#
# croak 'bstreq() is an instance method, not a class method'
# unless $selfref;
# croak 'Wrong number of arguments for bstreq()' unless @_ == 1;
#
# my $cmp = $self -> bstrcmp(shift);
# return defined($cmp) && ! $cmp;
#}
#
#sub bstrne {
# my $self = shift;
# my $selfref = ref $self;
# my $class = $selfref || $self;
#
# croak 'bstrne() is an instance method, not a class method'
# unless $selfref;
# croak 'Wrong number of arguments for bstrne()' unless @_ == 1;
#
# my $cmp = $self -> bstrcmp(shift);
# return defined($cmp) && ! $cmp ? '' : 1;
#}
#
#sub bstrlt {
# my $self = shift;
# my $selfref = ref $self;
# my $class = $selfref || $self;
#
# croak 'bstrlt() is an instance method, not a class method'
# unless $selfref;
# croak 'Wrong number of arguments for bstrlt()' unless @_ == 1;
#
# my $cmp = $self -> bstrcmp(shift);
# return defined($cmp) && $cmp bstrcmp(shift);
# return defined($cmp) && $cmp bstrcmp(shift);
# return defined($cmp) && $cmp > 0;
#}
#
#sub bstrge {
# my $self = shift;
# my $selfref = ref $self;
# my $class = $selfref || $self;
#
# croak 'bstrge() is an instance method, not a class method'
# unless $selfref;
# croak 'Wrong number of arguments for bstrge()' unless @_ == 1;
#
# my $cmp = $self -> bstrcmp(shift);
# return defined($cmp) && $cmp >= 0;
#}
sub badd {
# add second arg (BINT or string) to first (BINT) (modifies first)
# return result as BINT
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x->modify('badd');
return $upgrade->badd($upgrade->new($x), $upgrade->new($y), @r) if defined $upgrade &&
((!$x->isa($class)) || (!$y->isa($class)));
$r[3] = $y; # no push!
# inf and NaN handling
if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/) {
# NaN first
return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
# inf handling
if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/)) {
# +inf++inf or -inf+-inf => same, rest is NaN
return $x if $x->{sign} eq $y->{sign};
return $x->bnan();
}
# +-inf + something => +inf
# something +-inf => +-inf
$x->{sign} = $y->{sign}, return $x if $y->{sign} =~ /^[+-]inf$/;
return $x;
}
my ($sx, $sy) = ($x->{sign}, $y->{sign}); # get signs
if ($sx eq $sy) {
$x->{value} = $LIB->_add($x->{value}, $y->{value}); # same sign, abs add
} else {
my $a = $LIB->_acmp ($y->{value}, $x->{value}); # absolute compare
if ($a > 0) {
$x->{value} = $LIB->_sub($y->{value}, $x->{value}, 1); # abs sub w/ swap
$x->{sign} = $sy;
} elsif ($a == 0) {
# speedup, if equal, set result to 0
$x->{value} = $LIB->_zero();
$x->{sign} = '+';
} else # a {value} = $LIB->_sub($x->{value}, $y->{value}); # abs sub
}
}
$x->round(@r);
}
sub bsub {
# (BINT or num_str, BINT or num_str) return BINT
# subtract second arg from first, modify first
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x -> modify('bsub');
return $upgrade -> bsub($upgrade -> new($x), $upgrade -> new($y), @r)
if defined $upgrade && (!$x -> isa($class) || !$y -> isa($class));
return $x -> round(@r) if $y -> is_zero();
# To correctly handle the lone special case $x -> bsub($x), we note the
# sign of $x, then flip the sign from $y, and if the sign of $x did change,
# too, then we caught the special case:
my $xsign = $x -> {sign};
$y -> {sign} =~ tr/+-/-+/; # does nothing for NaN
if ($xsign ne $x -> {sign}) {
# special case of $x -> bsub($x) results in 0
return $x -> bzero(@r) if $xsign =~ /^[+-]$/;
return $x -> bnan(); # NaN, -inf, +inf
}
$x -> badd($y, @r); # badd does not leave internal zeros
$y -> {sign} =~ tr/+-/-+/; # refix $y (does nothing for NaN)
$x; # already rounded by badd() or no rounding
}
sub bmul {
# multiply the first number by the second number
# (BINT or num_str, BINT or num_str) return BINT
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x->modify('bmul');
return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan));
# inf handling
if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) {
return $x->bnan() if $x->is_zero() || $y->is_zero();
# result will always be +-inf:
# +inf * +/+inf => +inf, -inf * -/-inf => +inf
# +inf * -/-inf => -inf, -inf * +/+inf => -inf
return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
return $x->binf('-');
}
return $upgrade->bmul($x, $upgrade->new($y), @r)
if defined $upgrade && !$y->isa($class);
$r[3] = $y; # no push here
$x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-'; # +1 * +1 or -1 * -1 => +
$x->{value} = $LIB->_mul($x->{value}, $y->{value}); # do actual math
$x->{sign} = '+' if $LIB->_is_zero($x->{value}); # no -0
$x->round(@r);
}
sub bmuladd {
# multiply two numbers and then add the third to the result
# (BINT or num_str, BINT or num_str, BINT or num_str) return BINT
# set up parameters
my ($class, $x, $y, $z, @r) = objectify(3, @_);
return $x if $x->modify('bmuladd');
return $x->bnan() if (($x->{sign} eq $nan) ||
($y->{sign} eq $nan) ||
($z->{sign} eq $nan));
# inf handling of x and y
if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) {
return $x->bnan() if $x->is_zero() || $y->is_zero();
# result will always be +-inf:
# +inf * +/+inf => +inf, -inf * -/-inf => +inf
# +inf * -/-inf => -inf, -inf * +/+inf => -inf
return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/);
return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/);
return $x->binf('-');
}
# inf handling x*y and z
if (($z->{sign} =~ /^[+-]inf$/)) {
# something +-inf => +-inf
$x->{sign} = $z->{sign}, return $x if $z->{sign} =~ /^[+-]inf$/;
}
return $upgrade->bmuladd($x, $upgrade->new($y), $upgrade->new($z), @r)
if defined $upgrade && (!$y->isa($class) || !$z->isa($class) || !$x->isa($class));
# TODO: what if $y and $z have A or P set?
$r[3] = $z; # no push here
$x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-'; # +1 * +1 or -1 * -1 => +
$x->{value} = $LIB->_mul($x->{value}, $y->{value}); # do actual math
$x->{sign} = '+' if $LIB->_is_zero($x->{value}); # no -0
my ($sx, $sz) = ( $x->{sign}, $z->{sign} ); # get signs
if ($sx eq $sz) {
$x->{value} = $LIB->_add($x->{value}, $z->{value}); # same sign, abs add
} else {
my $a = $LIB->_acmp ($z->{value}, $x->{value}); # absolute compare
if ($a > 0) {
$x->{value} = $LIB->_sub($z->{value}, $x->{value}, 1); # abs sub w/ swap
$x->{sign} = $sz;
} elsif ($a == 0) {
# speedup, if equal, set result to 0
$x->{value} = $LIB->_zero();
$x->{sign} = '+';
} else # a {value} = $LIB->_sub($x->{value}, $z->{value}); # abs sub
}
}
$x->round(@r);
}
sub bdiv {
# This does floored division, where the quotient is floored, i.e., rounded
# towards negative infinity. As a consequence, the remainder has the same
# sign as the divisor.
# Set up parameters.
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify() is costly, so avoid it if we can.
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x -> modify('bdiv');
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(), $class -> bnan()) : $x -> bnan();
}
# 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();
}
if ($x -> is_zero()) {
$x -> bnan();
} else {
$x -> binf($x -> {sign});
}
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() if $wantarray;
if ($y -> is_inf()) {
$x -> bnan();
} else {
my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
$x -> binf($sign);
}
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 = -1 -5 % inf = inf
# 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 = -1 5 % -inf = -inf
if ($y -> is_inf()) {
my $rem;
if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
$rem = $x -> copy() if $wantarray;
$x -> bzero();
} else {
$rem = $class -> binf($y -> {sign}) if $wantarray;
$x -> bone('-');
}
return $wantarray ? ($x, $rem) : $x;
}
# At this point, both the numerator and denominator are finite numbers, and
# the denominator (divisor) is non-zero.
return $upgrade -> bdiv($upgrade -> new($x), $upgrade -> new($y), @r)
if defined $upgrade;
$r[3] = $y; # no push!
# Inialize remainder.
my $rem = $class -> bzero();
# 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 -> bone();
} else {
($x -> {value}, $rem -> {value}) =
$LIB -> _div($x -> {value}, $y -> {value});
if ($LIB -> _is_zero($rem -> {value})) {
if ($xsign eq $ysign || $LIB -> _is_zero($x -> {value})) {
$x -> {sign} = '+';
} else {
$x -> {sign} = '-';
}
} else {
if ($xsign eq $ysign) {
$x -> {sign} = '+';
} else {
if ($xsign eq '+') {
$x -> badd(1);
} else {
$x -> bsub(1);
}
$x -> {sign} = '-';
}
}
}
$x -> round(@r);
if ($wantarray) {
unless ($LIB -> _is_zero($rem -> {value})) {
if ($xsign ne $ysign) {
$rem = $y -> copy() -> babs() -> bsub($rem);
}
$rem -> {sign} = $ysign;
}
$rem -> {_a} = $x -> {_a};
$rem -> {_p} = $x -> {_p};
$rem -> round(@r);
return ($x, $rem);
}
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]), @_);
# objectify is costly, so avoid it if we can.
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
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(), $class -> bnan()) : $x -> bnan();
}
# 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();
}
if ($x -> is_zero()) {
$x -> bnan();
} else {
$x -> binf($x -> {sign});
}
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() if $wantarray;
if ($y -> is_inf()) {
$x -> bnan();
} else {
my $sign = $x -> bcmp(0) == $y -> bcmp(0) ? '+' : '-';
$x -> binf($sign);
}
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;
$rem = $x -> copy() if $wantarray;
$x -> bzero();
return $wantarray ? ($x, $rem) : $x;
}
return $upgrade -> btdiv($upgrade -> new($x), $upgrade -> new($y), @r)
if defined $upgrade;
$r[3] = $y; # no push!
# Inialize remainder.
my $rem = $class -> bzero();
# 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 -> bone();
} else {
($x -> {value}, $rem -> {value}) =
$LIB -> _div($x -> {value}, $y -> {value});
$x -> {sign} = $xsign eq $ysign ? '+' : '-';
$x -> {sign} = '+' if $LIB -> _is_zero($x -> {value});
$x -> round(@r);
}
if (wantarray) {
$rem -> {sign} = $xsign;
$rem -> {sign} = '+' if $LIB -> _is_zero($rem -> {value});
$rem -> {_a} = $x -> {_a};
$rem -> {_p} = $x -> {_p};
$rem -> round(@r);
return ($x, $rem);
}
return $x;
}
sub bmod {
# This is the remainder after floored division.
# Set up parameters.
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x -> modify('bmod');
$r[3] = $y; # no push!
# At least one argument is NaN.
if ($x -> is_nan() || $y -> is_nan()) {
return $x -> bnan();
}
# Modulo zero. See documentation for bdiv().
if ($y -> is_zero()) {
return $x;
}
# Numerator (dividend) is +/-inf.
if ($x -> is_inf()) {
return $x -> bnan();
}
# Denominator (divisor) is +/-inf.
if ($y -> is_inf()) {
if ($x -> is_zero() || $x -> bcmp(0) == $y -> bcmp(0)) {
return $x;
} else {
return $x -> binf($y -> sign());
}
}
# Calc new sign and in case $y == +/- 1, return $x.
$x -> {value} = $LIB -> _mod($x -> {value}, $y -> {value});
if ($LIB -> _is_zero($x -> {value})) {
$x -> {sign} = '+'; # do not leave -0
} else {
$x -> {value} = $LIB -> _sub($y -> {value}, $x -> {value}, 1) # $y-$x
if ($x -> {sign} ne $y -> {sign});
$x -> {sign} = $y -> {sign};
}
$x -> round(@r);
}
sub btmod {
# Remainder after truncated division.
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x -> modify('btmod');
# At least one argument is NaN.
if ($x -> is_nan() || $y -> is_nan()) {
return $x -> bnan();
}
# Modulo zero. See documentation for btdiv().
if ($y -> is_zero()) {
return $x;
}
# Numerator (dividend) is +/-inf.
if ($x -> is_inf()) {
return $x -> bnan();
}
# Denominator (divisor) is +/-inf.
if ($y -> is_inf()) {
return $x;
}
return $upgrade -> btmod($upgrade -> new($x), $upgrade -> new($y), @r)
if defined $upgrade;
$r[3] = $y; # no push!
my $xsign = $x -> {sign};
$x -> {value} = $LIB -> _mod($x -> {value}, $y -> {value});
$x -> {sign} = $xsign;
$x -> {sign} = '+' if $LIB -> _is_zero($x -> {value});
$x -> round(@r);
return $x;
}
sub bmodinv {
# Return modular multiplicative inverse:
#
# z is the modular inverse of x (mod y) if and only if
#
# x*z â¡ 1 (mod y)
#
# If the modulus y is larger than one, x and z are relative primes (i.e.,
# their greatest common divisor is one).
#
# If no modular multiplicative inverse exists, NaN is returned.
# set up parameters
my ($class, $x, $y, @r) = (undef, @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x->modify('bmodinv');
# Return NaN if one or both arguments is +inf, -inf, or nan.
return $x->bnan() if ($y->{sign} !~ /^[+-]$/ ||
$x->{sign} !~ /^[+-]$/);
# Return NaN if $y is zero; 1 % 0 makes no sense.
return $x->bnan() if $y->is_zero();
# Return 0 in the trivial case. $x % 1 or $x % -1 is zero for all finite
# integers $x.
return $x->bzero() if ($y->is_one() ||
$y->is_one('-'));
# Return NaN if $x = 0, or $x modulo $y is zero. The only valid case when
# $x = 0 is when $y = 1 or $y = -1, but that was covered above.
#
# Note that computing $x modulo $y here affects the value we'll feed to
# $LIB->_modinv() below when $x and $y have opposite signs. E.g., if $x =
# 5 and $y = 7, those two values are fed to _modinv(), but if $x = -5 and
# $y = 7, the values fed to _modinv() are $x = 2 (= -5 % 7) and $y = 7.
# The value if $x is affected only when $x and $y have opposite signs.
$x->bmod($y);
return $x->bnan() if $x->is_zero();
# Compute the modular multiplicative inverse of the absolute values. We'll
# correct for the signs of $x and $y later. Return NaN if no GCD is found.
($x->{value}, $x->{sign}) = $LIB->_modinv($x->{value}, $y->{value});
return $x->bnan() if !defined $x->{value};
# Library inconsistency workaround: _modinv() in Math::BigInt::GMP versions
# {sign} = '+' unless defined $x->{sign};
# When one or both arguments are negative, we have the following
# relations. If x and y are positive:
#
# modinv(-x, -y) = -modinv(x, y)
# modinv(-x, y) = y - modinv(x, y) = -modinv(x, y) (mod y)
# modinv( x, -y) = modinv(x, y) - y = modinv(x, y) (mod -y)
# We must swap the sign of the result if the original $x is negative.
# However, we must compensate for ignoring the signs when computing the
# inverse modulo. The net effect is that we must swap the sign of the
# result if $y is negative.
$x -> bneg() if $y->{sign} eq '-';
# Compute $x modulo $y again after correcting the sign.
$x -> bmod($y) if $x->{sign} ne $y->{sign};
return $x;
}
sub bmodpow {
# Modular exponentiation. Raises 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) = objectify(3, @_);
return $num if $num->modify('bmodpow');
# When the exponent 'e' is negative, use the following relation, which is
# based on finding the multiplicative inverse 'd' of 'b' modulo 'm':
#
# b^(-e) (mod m) = d^e (mod m) where b*d = 1 (mod m)
$num->bmodinv($mod) if ($exp->{sign} eq '-');
# Check for valid input. All operands must be finite, and the modulus must be
# non-zero.
return $num->bnan() if ($num->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf
$exp->{sign} =~ /NaN|inf/ || # NaN, -inf, +inf
$mod->{sign} =~ /NaN|inf/); # NaN, -inf, +inf
# Modulo zero. See documentation for Math::BigInt's bmod() method.
if ($mod -> is_zero()) {
if ($num -> is_zero()) {
return $class -> bnan();
} else {
return $num -> copy();
}
}
# Compute 'a (mod m)', ignoring the signs on 'a' and 'm'. If the resulting
# value is zero, the output is also zero, regardless of the signs on 'a' and
# 'm'.
my $value = $LIB->_modpow($num->{value}, $exp->{value}, $mod->{value});
my $sign = '+';
# If the resulting value is non-zero, we have four special cases, depending
# on the signs on 'a' and 'm'.
unless ($LIB->_is_zero($value)) {
# There is a negative sign on 'a' (= $num**$exp) only if the number we
# are exponentiating ($num) is negative and the exponent ($exp) is odd.
if ($num->{sign} eq '-' && $exp->is_odd()) {
# When both the number 'a' and the modulus 'm' have a negative sign,
# use this relation:
#
# -a (mod -m) = -(a (mod m))
if ($mod->{sign} eq '-') {
$sign = '-';
}
# When only the number 'a' has a negative sign, use this relation:
#
# -a (mod m) = m - (a (mod m))
else {
# Use copy of $mod since _sub() modifies the first argument.
my $mod = $LIB->_copy($mod->{value});
$value = $LIB->_sub($mod, $value);
$sign = '+';
}
} else {
# When only the modulus 'm' has a negative sign, use this relation:
#
# a (mod -m) = (a (mod m)) - m
# = -(m - (a (mod m)))
if ($mod->{sign} eq '-') {
# Use copy of $mod since _sub() modifies the first argument.
my $mod = $LIB->_copy($mod->{value});
$value = $LIB->_sub($mod, $value);
$sign = '-';
}
# When neither the number 'a' nor the modulus 'm' have a negative
# sign, directly return the already computed value.
#
# (a (mod m))
}
}
$num->{value} = $value;
$num->{sign} = $sign;
return $num -> round(@r);
}
sub bpow {
# (BINT or num_str, BINT or num_str) return BINT
# compute power of two numbers -- stolen from Knuth Vol 2 pg 233
# modifies first argument
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x -> modify('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 -> is_zero();
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 -> is_zero();
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;
}
if ($x -> is_one("+")) {
return $x;
}
if ($x -> is_one("-")) {
return $x if $y -> is_odd();
return $x -> bneg();
}
# We don't support finite non-integers, so upgrade or return zero. The
# reason for returning zero, not NaN, is that all output is in the open
# interval (0,1), and truncating that to integer gives zero.
if ($y->{sign} eq '-' || !$y -> isa($class)) {
return $upgrade -> bpow($upgrade -> new($x), $y, @r)
if defined $upgrade;
return $x -> bzero();
}
$r[3] = $y; # no push!
$x->{value} = $LIB -> _pow($x->{value}, $y->{value});
$x->{sign} = $x -> is_negative() && $y -> is_odd() ? '-' : '+';
$x -> round(@r);
}
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);
# Don't objectify the base, since an undefined base, as in $x->blog() or
# $x->blog(undef) signals that the base is Euler's number.
if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
# E.g., Math::BigInt->blog(256, 2)
($class, $x, $base, @r) =
defined $_[2] ? objectify(2, @_) : objectify(1, @_);
} else {
# E.g., Math::BigInt::blog(256, 2) or $x->blog(2)
($class, $x, $base, @r) =
defined $_[1] ? objectify(2, @_) : objectify(1, @_);
}
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() if $x -> is_nan();
if (defined $base) {
$base = $class -> new($base) unless ref $base;
if ($base -> is_nan() || $base -> is_one()) {
return $x -> bnan();
} elsif ($base -> is_inf() || $base -> is_zero()) {
return $x -> bnan() if $x -> is_inf() || $x -> is_zero();
return $x -> bzero();
} elsif ($base -> is_negative()) { # -inf bzero() if $x -> is_one(); # x = 1
return $x -> bone() if $x == $base; # x = base
return $x -> bnan(); # otherwise
}
return $x -> bone() if $x == $base; # 0 = 2 and finite.
return $x -> binf('+') if $x -> is_inf(); # x = +/-inf
return $x -> bnan() if $x -> is_neg(); # -inf bzero() if $x -> is_one(); # x = 1
return $x -> binf('-') if $x -> is_zero(); # x = 0
# At this point we are done handling all exception cases and trivial cases.
return $upgrade -> blog($upgrade -> new($x), $base, @r) if defined $upgrade;
# fix for bug #24969:
# the default base is e (Euler's number) which is not an integer
if (!defined $base) {
require Math::BigFloat;
my $u = Math::BigFloat->blog(Math::BigFloat->new($x))->as_int();
# modify $x in place
$x->{value} = $u->{value};
$x->{sign} = $u->{sign};
return $x;
}
my ($rc) = $LIB->_log_int($x->{value}, $base->{value});
return $x->bnan() unless defined $rc; # not possible to take log?
$x->{value} = $rc;
$x->round(@r);
}
sub bexp {
# Calculate e ** $x (Euler's number to the power of X), truncated to
# an integer value.
my ($class, $x, @r) = ref($_[0]) ? (ref($_[0]), @_) : objectify(1, @_);
return $x if $x->modify('bexp');
# inf, -inf, NaN, NaN
return $x->bnan() if $x->{sign} eq 'NaN';
return $x->bone() if $x->is_zero();
return $x if $x->{sign} eq '+inf';
return $x->bzero() if $x->{sign} eq '-inf';
my $u;
{
# run through Math::BigFloat unless told otherwise
require Math::BigFloat unless defined $upgrade;
local $upgrade = 'Math::BigFloat' unless defined $upgrade;
# calculate result, truncate it to integer
$u = $upgrade->bexp($upgrade->new($x), @r);
}
if (defined $upgrade) {
$x = $u;
} else {
$u = $u->as_int();
# modify $x in place
$x->{value} = $u->{value};
$x->round(@r);
}
}
sub bnok {
# Calculate n over k (binomial coefficient or "choose" function) as
# integer.
# Set up parameters.
my ($self, $n, $k, @r) = (ref($_[0]), @_);
# Objectify is costly, so avoid it.
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($self, $n, $k, @r) = objectify(2, @_);
}
return $n if $n->modify('bnok');
# All cases where at least one argument is NaN.
return $n->bnan() if $n->{sign} eq 'NaN' || $k->{sign} eq 'NaN';
# All cases where at least one argument is +/-inf.
if ($n -> is_inf()) {
if ($k -> is_inf()) { # bnok(+/-inf,+/-inf)
return $n -> bnan();
} elsif ($k -> is_neg()) { # bnok(+/-inf,k), k bzero();
} elsif ($k -> is_zero()) { # bnok(+/-inf,k), k = 0
return $n -> bone();
} else {
if ($n -> is_inf("+")) { # bnok(+inf,k), 0 binf("+");
} else { # bnok(-inf,k), k > 0
my $sign = $k -> is_even() ? "+" : "-";
return $n -> binf($sign);
}
}
}
elsif ($k -> is_inf()) { # bnok(n,+/-inf), -inf bnan();
}
# At this point, both n and k are real numbers.
my $sign = 1;
if ($n >= 0) {
if ($k $n) {
return $n -> bzero();
}
} else {
if ($k >= 0) {
# n = 0: bnok(n,k) = (-1)^k * bnok(-n+k-1,k)
$sign = (-1) ** $k;
$n -> bneg() -> badd($k) -> bdec();
} elsif ($k copy();
$n -> bone() -> badd($k) -> bneg();
$k = $k -> copy();
$k -> bneg() -> badd($x0);
} else {
# n bzero();
}
}
$n->{value} = $LIB->_nok($n->{value}, $k->{value});
$n -> bneg() if $sign == -1;
$n->round(@r);
}
sub buparrow {
my $a = shift;
my $y = $a -> uparrow(@_);
$a -> {value} = $y -> {value};
return $a;
}
sub uparrow {
# Knuth's up-arrow notation buparrow(a, n, b)
#
# The following is a simple, recursive implementation of the up-arrow
# notation, just to show the idea. Such implementations cause "Deep
# recursion on subroutine ..." warnings, so we use a faster, non-recursive
# algorithm below with @_ as a stack.
#
# sub buparrow {
# my ($a, $n, $b) = @_;
# return $a ** $b if $n == 1;
# return $a * $b if $n == 0;
# return 1 if $b == 0;
# return buparrow($a, $n - 1, buparrow($a, $n, $b - 1));
# }
my ($a, $b, $n) = @_;
my $class = ref $a;
croak("a must be non-negative") if $a = 3) {
# return $a ** $b if $n == 1;
if ($_[-2] == 1) {
my ($a, $n, $b) = splice @_, -3;
push @_, $a ** $b;
next;
}
# return $a * $b if $n == 0;
if ($_[-2] == 0) {
my ($a, $n, $b) = splice @_, -3;
push @_, $a * $b;
next;
}
# return 1 if $b == 0;
if ($_[-1] == 0) {
splice @_, -3;
push @_, $class -> bone();
next;
}
# return buparrow($a, $n - 1, buparrow($a, $n, $b - 1));
my ($a, $n, $b) = splice @_, -3;
push @_, ($a, $n - 1,
$a, $n, $b - 1);
}
pop @_;
}
sub backermann {
my $m = shift;
my $y = $m -> ackermann(@_);
$m -> {value} = $y -> {value};
return $m;
}
sub ackermann {
# Ackermann's function ackermann(m, n)
#
# The following is a simple, recursive implementation of the ackermann
# function, just to show the idea. Such implementations cause "Deep
# recursion on subroutine ..." warnings, so we use a faster, non-recursive
# algorithm below with @_ as a stack.
#
# sub ackermann {
# my ($m, $n) = @_;
# return $n + 1 if $m == 0;
# return ackermann($m - 1, 1) if $m > 0 && $n == 0;
# return ackermann($m - 1, ackermann($m, $n - 1) if $m > 0 && $n > 0;
# }
my ($m, $n) = @_;
my $class = ref $m;
croak("m must be non-negative") if $m new("2");
my $three = $class -> new("3");
my $thirteen = $class -> new("13");
$n = pop;
$n = $class -> new($n) unless ref($n);
while (@_) {
my $m = pop;
if ($m > $three) {
push @_, (--$m) x $n;
while (--$m >= $three) {
push @_, $m;
}
$n = $thirteen;
} elsif ($m == $three) {
$n = $class -> bone() -> blsft($n + $three) -> bsub($three);
} elsif ($m == $two) {
$n -> bmul($two) -> badd($three);
} elsif ($m >= 0) {
$n -> badd($m) -> binc();
} else {
die "negative m!";
}
}
$n;
}
sub bsin {
# Calculate sinus(x) to N digits. Unless upgrading is in effect, returns the
# result truncated to an integer.
my ($class, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return $x if $x->modify('bsin');
return $x->bnan() if $x->{sign} !~ /^[+-]\z/; # -inf +inf or NaN => NaN
return $upgrade -> bsin($upgrade -> new($x, @r)) if defined $upgrade;
require Math::BigFloat;
# calculate the result and truncate it to integer
my $t = Math::BigFloat->new($x)->bsin(@r)->as_int();
$x->bone() if $t->is_one();
$x->bzero() if $t->is_zero();
$x->round(@r);
}
sub bcos {
# Calculate cosinus(x) to N digits. Unless upgrading is in effect, returns the
# result truncated to an integer.
my ($class, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return $x if $x->modify('bcos');
return $x->bnan() if $x->{sign} !~ /^[+-]\z/; # -inf +inf or NaN => NaN
return $upgrade -> bcos($upgrade -> new($x), @r) if defined $upgrade;
require Math::BigFloat;
# calculate the result and truncate it to integer
my $t = Math::BigFloat -> bcos(Math::BigFloat -> new($x), @r) -> as_int();
$x->bone() if $t->is_one();
$x->bzero() if $t->is_zero();
$x->round(@r);
}
sub batan {
# Calculate arcus tangens of x to N digits. Unless upgrading is in effect, returns the
# result truncated to an integer.
my ($class, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return $x if $x->modify('batan');
return $x->bnan() if $x->{sign} !~ /^[+-]\z/; # -inf +inf or NaN => NaN
return $upgrade->new($x)->batan(@r) if defined $upgrade;
# calculate the result and truncate it to integer
my $tmp = Math::BigFloat->new($x)->batan(@r);
$x->{value} = $LIB->_new($tmp->as_int()->bstr());
$x->round(@r);
}
sub batan2 {
# calculate arcus tangens of ($y/$x)
# set up parameters
my ($class, $y, $x, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $y, $x, @r) = objectify(2, @_);
}
return $y if $y->modify('batan2');
return $y->bnan() if ($y->{sign} eq $nan) || ($x->{sign} eq $nan);
# Y X
# != 0 -inf result is +- pi
if ($x->is_inf() || $y->is_inf()) {
# upgrade to Math::BigFloat etc.
return $upgrade->new($y)->batan2($upgrade->new($x), @r) if defined $upgrade;
if ($y->is_inf()) {
if ($x->{sign} eq '-inf') {
# calculate 3 pi/4 => 2.3.. => 2
$y->bone(substr($y->{sign}, 0, 1));
$y->bmul($class->new(2));
} elsif ($x->{sign} eq '+inf') {
# calculate pi/4 => 0.7 => 0
$y->bzero();
} else {
# calculate pi/2 => 1.5 => 1
$y->bone(substr($y->{sign}, 0, 1));
}
} else {
if ($x->{sign} eq '+inf') {
# calculate pi/4 => 0.7 => 0
$y->bzero();
} else {
# PI => 3.1415.. => 3
$y->bone(substr($y->{sign}, 0, 1));
$y->bmul($class->new(3));
}
}
return $y;
}
return $upgrade->new($y)->batan2($upgrade->new($x), @r) if defined $upgrade;
require Math::BigFloat;
my $r = Math::BigFloat->new($y)
->batan2(Math::BigFloat->new($x), @r)
->as_int();
$x->{value} = $r->{value};
$x->{sign} = $r->{sign};
$x;
}
sub bsqrt {
# calculate square root of $x
my ($class, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return $x if $x->modify('bsqrt');
return $x->bnan() if $x->{sign} !~ /^\+/; # -x or -inf or NaN => NaN
return $x if $x->{sign} eq '+inf'; # sqrt(+inf) == inf
return $upgrade->bsqrt($x, @r) if defined $upgrade;
$x->{value} = $LIB->_sqrt($x->{value});
$x->round(@r);
}
sub broot {
# calculate $y'th root of $x
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
$y = $class->new(2) unless defined $y;
# objectify is costly, so avoid it
if ((!ref($x)) || (ref($x) ne ref($y))) {
($class, $x, $y, @r) = objectify(2, $class || $class, @_);
}
return $x if $x->modify('broot');
# NaN handling: $x ** 1/0, x or y NaN, or y inf/-inf or y == 0
return $x->bnan() if $x->{sign} !~ /^\+/ || $y->is_zero() ||
$y->{sign} !~ /^\+$/;
return $x->round(@r)
if $x->is_zero() || $x->is_one() || $x->is_inf() || $y->is_one();
return $upgrade->new($x)->broot($upgrade->new($y), @r) if defined $upgrade;
$x->{value} = $LIB->_root($x->{value}, $y->{value});
$x->round(@r);
}
sub bfac {
# (BINT or num_str, BINT or num_str) return BINT
# compute factorial number from $x, modify $x in place
my ($class, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return $x if $x->modify('bfac') || $x->{sign} eq '+inf'; # inf => inf
return $x->bnan() if $x->{sign} ne '+'; # NaN, NaN
$x->{value} = $LIB->_fac($x->{value});
$x->round(@r);
}
sub bdfac {
# compute double factorial, modify $x in place
my ($class, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return $x if $x->modify('bdfac') || $x->{sign} eq '+inf'; # inf => inf
return $x->bnan() if $x->is_nan() || $x bone() if $x can('_dfac');
$x->{value} = $LIB->_dfac($x->{value});
$x->round(@r);
}
sub btfac {
# compute triple factorial, modify $x in place
my ($class, $x, @r) = objectify(1, @_);
return $x if $x->modify('btfac') || $x->{sign} eq '+inf'; # inf => inf
return $x->bnan() if $x->is_nan();
my $k = $class -> new("3");
return $x->bnan() if $x bone();
return $x->bone() if $x copy();
while ($f -> bsub($k) > $one) {
$x -> bmul($f);
}
$x->round(@r);
}
sub bmfac {
# compute multi-factorial
my ($class, $x, $k, @r) = objectify(2, @_);
return $x if $x->modify('bmfac') || $x->{sign} eq '+inf';
return $x->bnan() if $x->is_nan() || $k->is_nan() || $k bone();
return $x->bone() if $x copy();
while ($f -> bsub($k) > $one) {
$x -> bmul($f);
}
$x->round(@r);
}
sub bfib {
# compute Fibonacci number(s)
my ($class, $x, @r) = objectify(1, @_);
croak("bfib() requires a newer version of the $LIB library.")
unless $LIB->can('_fib');
return $x if $x->modify('bfib');
# List context.
if (wantarray) {
return () if $x -> is_nan();
croak("bfib() can't return an infinitely long list of numbers")
if $x -> is_inf();
# Use the backend library to compute the first $x Fibonacci numbers.
my @values = $LIB->_fib($x->{value});
# Make objects out of them. The last element in the array is the
# invocand.
for (my $i = 0 ; $i bzero();
$fib -> {value} = $values[$i];
$values[$i] = $fib;
}
$x -> {value} = $values[-1];
$values[-1] = $x;
# If negative, insert sign as appropriate.
if ($x -> is_neg()) {
for (my $i = 2 ; $i round(@r) } @values;
return @values;
}
# Scalar context.
else {
return $x if $x->modify('bdfac') || $x -> is_inf('+');
return $x->bnan() if $x -> is_nan() || $x -> is_inf('-');
$x->{sign} = $x -> is_neg() && $x -> is_even() ? '-' : '+';
$x->{value} = $LIB->_fib($x->{value});
return $x->round(@r);
}
}
sub blucas {
# compute Lucas number(s)
my ($class, $x, @r) = objectify(1, @_);
croak("blucas() requires a newer version of the $LIB library.")
unless $LIB->can('_lucas');
return $x if $x->modify('blucas');
# List context.
if (wantarray) {
return () if $x -> is_nan();
croak("blucas() can't return an infinitely long list of numbers")
if $x -> is_inf();
# Use the backend library to compute the first $x Lucas numbers.
my @values = $LIB->_lucas($x->{value});
# Make objects out of them. The last element in the array is the
# invocand.
for (my $i = 0 ; $i bzero();
$lucas -> {value} = $values[$i];
$values[$i] = $lucas;
}
$x -> {value} = $values[-1];
$values[-1] = $x;
# If negative, insert sign as appropriate.
if ($x -> is_neg()) {
for (my $i = 2 ; $i round(@r) } @values;
return @values;
}
# Scalar context.
else {
return $x if $x -> is_inf('+');
return $x->bnan() if $x -> is_nan() || $x -> is_inf('-');
$x->{sign} = $x -> is_neg() && $x -> is_even() ? '-' : '+';
$x->{value} = $LIB->_lucas($x->{value});
return $x->round(@r);
}
}
sub blsft {
# (BINT or num_str, BINT or num_str) return BINT
# compute x = 0
my ($class, $x, $y, $b, @r);
# Objectify the base only when it is defined, since an undefined base, as
# in $x->blsft(3) or $x->blog(3, undef) means use the default base 2.
if (!ref($_[0]) && $_[0] =~ /^[A-Za-z]|::/) {
# E.g., Math::BigInt->blog(256, 5, 2)
($class, $x, $y, $b, @r) =
defined $_[3] ? objectify(3, @_) : objectify(2, @_);
} else {
# E.g., Math::BigInt::blog(256, 5, 2) or $x->blog(5, 2)
($class, $x, $y, $b, @r) =
defined $_[2] ? objectify(3, @_) : objectify(2, @_);
}
return $x if $x -> modify('blsft');
return $x -> bnan() if ($x -> {sign} !~ /^[+-]$/ ||
$y -> {sign} !~ /^[+-]$/);
return $x -> round(@r) if $y -> is_zero();
$b = defined($b) ? $b -> numify() : 2;
# While some of the libraries support an arbitrarily large base, not all of
# them do, so rather than returning an incorrect result in those cases,
# disallow bases that don't work with all libraries.
my $uintmax = ~0;
croak("Base is too large.") if $b > $uintmax;
return $x -> bnan() if $b {sign} eq '-';
$x -> {value} = $LIB -> _lsft($x -> {value}, $y -> {value}, $b);
$x -> round(@r);
}
sub brsft {
# (BINT or num_str, BINT or num_str) return BINT
# compute x >> y, base n, y >= 0
# set up parameters
my ($class, $x, $y, $b, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, $b, @r) = objectify(2, @_);
}
return $x if $x -> modify('brsft');
return $x -> bnan() if ($x -> {sign} !~ /^[+-]$/ || $y -> {sign} !~ /^[+-]$/);
return $x -> round(@r) if $y -> is_zero();
return $x -> bzero(@r) if $x -> is_zero(); # 0 => 0
$b = 2 if !defined $b;
return $x -> bnan() if $b {sign} eq '-';
# this only works for negative numbers when shifting in base 2
if (($x -> {sign} eq '-') && ($b == 2)) {
return $x -> round(@r) if $x -> is_one('-'); # -1 => -1
if (!$y -> is_one()) {
# although this is O(N*N) in calc (as_bin!) it is O(N) in Pari et
# al but perhaps there is a better emulation for two's complement
# shift...
# if $y != 1, we must simulate it by doing:
# convert to bin, flip all bits, shift, and be done
$x -> binc(); # -3 => -2
my $bin = $x -> as_bin();
$bin =~ s/^-0b//; # strip '-0b' prefix
$bin =~ tr/10/01/; # flip bits
# now shift
if ($y >= CORE::length($bin)) {
$bin = '0'; # shifting to far right creates -1
# 0, because later increment makes
# that 1, attached '-' makes it '-1'
# because -1 >> x == -1 !
} else {
$bin =~ s/.{$y}$//; # cut off at the right side
$bin = '1' . $bin; # extend left side by one dummy '1'
$bin =~ tr/10/01/; # flip bits back
}
my $res = $class -> new('0b' . $bin); # add prefix and convert back
$res -> binc(); # remember to increment
$x -> {value} = $res -> {value}; # take over value
return $x -> round(@r); # we are done now, magic, isn't?
}
# x bdec(); # n == 2, but $y == 1: this fixes it
}
$x -> {value} = $LIB -> _rsft($x -> {value}, $y -> {value}, $b);
$x -> round(@r);
}
###############################################################################
# Bitwise methods
###############################################################################
sub band {
#(BINT or num_str, BINT or num_str) return BINT
# compute x & y
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x->modify('band');
$r[3] = $y; # no push!
return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
if ($x->{sign} eq '+' && $y->{sign} eq '+') {
$x->{value} = $LIB->_and($x->{value}, $y->{value});
} else {
($x->{value}, $x->{sign}) = $LIB->_sand($x->{value}, $x->{sign},
$y->{value}, $y->{sign});
}
return $x->round(@r);
}
sub bior {
#(BINT or num_str, BINT or num_str) return BINT
# compute x | y
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x->modify('bior');
$r[3] = $y; # no push!
return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
if ($x->{sign} eq '+' && $y->{sign} eq '+') {
$x->{value} = $LIB->_or($x->{value}, $y->{value});
} else {
($x->{value}, $x->{sign}) = $LIB->_sor($x->{value}, $x->{sign},
$y->{value}, $y->{sign});
}
return $x->round(@r);
}
sub bxor {
#(BINT or num_str, BINT or num_str) return BINT
# compute x ^ y
# set up parameters
my ($class, $x, $y, @r) = (ref($_[0]), @_);
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1]))) {
($class, $x, $y, @r) = objectify(2, @_);
}
return $x if $x->modify('bxor');
$r[3] = $y; # no push!
return $x->bnan() if ($x->{sign} !~ /^[+-]$/ || $y->{sign} !~ /^[+-]$/);
if ($x->{sign} eq '+' && $y->{sign} eq '+') {
$x->{value} = $LIB->_xor($x->{value}, $y->{value});
} else {
($x->{value}, $x->{sign}) = $LIB->_sxor($x->{value}, $x->{sign},
$y->{value}, $y->{sign});
}
return $x->round(@r);
}
sub bnot {
# (num_str or BINT) return BINT
# represent ~x as twos-complement number
# we don't need $class, so undef instead of ref($_[0]) make it slightly faster
my ($class, $x) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
return $x if $x->modify('bnot');
$x->binc()->bneg(); # binc already does round
}
###############################################################################
# Rounding methods
###############################################################################
sub round {
# Round $self according to given parameters, or given second argument's
# parameters or global defaults
# for speed reasons, _find_round_parameters is embedded here:
my ($self, $a, $p, $r, @args) = @_;
# $a accuracy, if given by caller
# $p precision, if given by caller
# $r round_mode, if given by caller
# @args all 'other' arguments (0 for unary, 1 for binary ops)
my $class = ref($self); # find out class of argument(s)
no strict 'refs';
# now pick $a or $p, but only if we have got "arguments"
if (!defined $a) {
foreach ($self, @args) {
# take the defined one, or if both defined, the one that is smaller
$a = $_->{_a} if (defined $_->{_a}) && (!defined $a || $_->{_a} -3, and 3 > 2
$p = $_->{_p} if (defined $_->{_p}) && (!defined $p || $_->{_p} > $p);
}
}
# if still none defined, use globals
unless (defined $a || defined $p) {
$a = ${"$class\::accuracy"};
$p = ${"$class\::precision"};
}
# A == 0 is useless, so undef it to signal no rounding
$a = undef if defined $a && $a == 0;
# no rounding today?
return $self unless defined $a || defined $p; # early out
# set A and set P is an fatal error
return $self->bnan() if defined $a && defined $p;
$r = ${"$class\::round_mode"} unless defined $r;
if ($r !~ /^(even|odd|[+-]inf|zero|trunc|common)$/) {
croak("Unknown round mode '$r'");
}
# now round, by calling either bround or bfround:
if (defined $a) {
$self->bround(int($a), $r) if !defined $self->{_a} || $self->{_a} >= $a;
} else { # both can't be undefined due to early out
$self->bfround(int($p), $r) if !defined $self->{_p} || $self->{_p} bnorm(), but $x
my $x = shift;
$x = __PACKAGE__->new($x) unless ref $x;
my ($scale, $mode) = $x->_scale_a(@_);
return $x if !defined $scale || $x->modify('bround'); # no-op
if ($x->is_zero() || $scale == 0) {
$x->{_a} = $scale if !defined $x->{_a} || $x->{_a} > $scale; # 3 > 2
return $x;
}
return $x if $x->{sign} !~ /^[+-]$/; # inf, NaN
# we have fewer digits than we want to scale to
my $len = $x->length();
# convert $scale to a scalar in case it is an object (put's a limit on the
# number length, but this would already limited by memory constraints), makes
# it faster
$scale = $scale->numify() if ref ($scale);
# scale -len (not >=!)
if (($scale = $len)) {
$x->{_a} = $scale if !defined $x->{_a} || $x->{_a} > $scale; # 3 > 2
return $x;
}
# count of 0's to pad, from left (+) or right (-): 9 - +6 => 3, or |-6| => 6
my ($pad, $digit_round, $digit_after);
$pad = $len - $scale;
$pad = abs($scale-1) if $scale decimal
# getting the entire string is also costly, but we need to do it only once
my $xs = $LIB->_str($x->{value});
my $pl = -$pad-1;
# pad: 123: 0 => -1, at 1 => -2, at 2 => -3, at 3 => -4
# pad+1: 123: 0 => 0, at 1 => -1, at 2 => -2, at 3 => -3
$digit_round = '0';
$digit_round = substr($xs, $pl, 1) if $pad = $len;
$digit_after = '0';
$digit_after = substr($xs, $pl, 1) if $pad > 0;
# in case of 01234 we round down, for 6789 up, and only in case 5 we look
# closer at the remaining digits of the original $x, remember decision
my $round_up = 1; # default round up
$round_up -- if
($mode eq 'trunc') || # trunc by round down
($digit_after =~ /[01234]/) || # round down anyway,
# 6789 => round up
($digit_after eq '5') && # not 5000...0000
($x->_scan_for_nonzero($pad, $xs, $len) == 0) &&
(
($mode eq 'even') && ($digit_round =~ /[24680]/) ||
($mode eq 'odd') && ($digit_round =~ /[13579]/) ||
($mode eq '+inf') && ($x->{sign} eq '-') ||
($mode eq '-inf') && ($x->{sign} eq '+') ||
($mode eq 'zero') # round down if zero, sign adjusted below
);
my $put_back = 0; # not yet modified
if (($pad > 0) && ($pad "0"
$put_back = 1; # need to put back
} elsif ($pad > $len) {
$x->bzero(); # round to '0'
}
if ($round_up) { # what gave test above?
$put_back = 1; # need to put back
$pad = $len, $xs = '0' x $pad if $scale 1.0
# we modify directly the string variant instead of creating a number and
# adding it, since that is faster (we already have the string)
my $c = 0;
$pad ++; # for $pad == $len case
while ($pad early out
}
$xs = '1'.$xs if $c == 0;
}
$x->{value} = $LIB->_new($xs) if $put_back == 1; # put back, if needed
$x->{_a} = $scale if $scale >= 0;
if ($scale {_a} = $len+$scale;
$x->{_a} = 0 if $scale round to integer
my $x = shift;
my $class = ref($x) || $x;
$x = $class->new($x) unless ref $x;
my ($scale, $mode) = $x->_scale_p(@_);
return $x if !defined $scale || $x->modify('bfround'); # no-op
# no-op for Math::BigInt objects if $n bround($x->length()-$scale, $mode) if $scale > 0;
delete $x->{_a}; # delete to save memory
$x->{_p} = $scale; # store new _p
$x;
}
sub fround {
# Exists to make life easier for switch between MBF and MBI (should we
# autoload fxxx() like MBF does for bxxx()?)
my $x = shift;
$x = __PACKAGE__->new($x) unless ref $x;
$x->bround(@_);
}
sub bfloor {
# round towards minus infinity; no-op since it's already integer
my ($class, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
$x->round(@r);
}
sub bceil {
# round towards plus infinity; no-op since it's already int
my ($class, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
$x->round(@r);
}
sub bint {
# round towards zero; no-op since it's already integer
my ($class, $x, @r) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
$x->round(@r);
}
###############################################################################
# Other mathematical methods
###############################################################################
sub bgcd {
# (BINT or num_str, BINT or num_str) return BINT
# does not modify arguments, but returns new object
# GCD -- Euclid's algorithm, variant C (Knuth Vol 3, pg 341 ff)
my ($class, @args) = objectify(0, @_);
my $x = shift @args;
$x = ref($x) && $x -> isa($class) ? $x -> copy() : $class -> new($x);
return $class->bnan() if $x->{sign} !~ /^[+-]$/; # x NaN?
while (@args) {
my $y = shift @args;
$y = $class->new($y) unless ref($y) && $y -> isa($class);
return $class->bnan() if $y->{sign} !~ /^[+-]$/; # y NaN?
$x->{value} = $LIB->_gcd($x->{value}, $y->{value});
last if $LIB->_is_one($x->{value});
}
return $x -> babs();
}
sub blcm {
# (BINT or num_str, BINT or num_str) return BINT
# does not modify arguments, but returns new object
# Least Common Multiple
my ($class, @args) = objectify(0, @_);
my $x = shift @args;
$x = ref($x) && $x -> isa($class) ? $x -> copy() : $class -> new($x);
return $class->bnan() if $x->{sign} !~ /^[+-]$/; # x NaN?
while (@args) {
my $y = shift @args;
$y = $class -> new($y) unless ref($y) && $y -> isa($class);
return $x->bnan() if $y->{sign} !~ /^[+-]$/; # y not integer
$x -> {value} = $LIB->_lcm($x -> {value}, $y -> {value});
}
return $x -> babs();
}
###############################################################################
# Object property methods
###############################################################################
sub sign {
# return the sign of the number: +/-/-inf/+inf/NaN
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
$x->{sign};
}
sub digit {
# return the nth decimal digit, negative values count backward, 0 is right
my ($class, $x, $n) = ref($_[0]) ? (undef, @_) : objectify(1, @_);
$n = $n->numify() if ref($n);
$LIB->_digit($x->{value}, $n || 0);
}
sub bdigitsum {
# like digitsum(), but assigns the result to the invocand
my $x = shift;
return $x if $x -> is_nan();
return $x -> bnan() if $x -> is_inf();
$x -> {value} = $LIB -> _digitsum($x -> {value});
$x -> {sign} = '+';
return $x;
}
sub digitsum {
# compute sum of decimal digits and return it
my $x = shift;
my $class = ref $x;
return $class -> bnan() if $x -> is_nan();
return $class -> bnan() if $x -> is_inf();
my $y = $class -> bzero();
$y -> {value} = $LIB -> _digitsum($x -> {value});
return $y;
}
sub length {
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
my $e = $LIB->_len($x->{value});
wantarray ? ($e, 0) : $e;
}
sub exponent {
# return a copy of the exponent (here always 0, NaN or 1 for $m == 0)
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
if ($x->{sign} !~ /^[+-]$/) {
my $s = $x->{sign};
$s =~ s/^[+-]//; # NaN, -inf, +inf => NaN or inf
return $class->new($s);
}
return $class->bzero() if $x->is_zero();
# 12300 => 2 trailing zeros => exponent is 2
$class->new($LIB->_zeros($x->{value}));
}
sub mantissa {
# return the mantissa (compatible to Math::BigFloat, e.g. reduced)
my ($class, $x) = ref($_[0]) ? (ref($_[0]), $_[0]) : objectify(1, @_);
if ($x->{sign} !~ /^[+-]$/) {
# for NaN, +inf, -inf: keep the sign
return $class->new($x->{sign});
}
my $m = $x->copy();
delete $m->{_p};
delete $m->{_a};
# that's a bit inefficient:
my $zeros = $LIB->_zeros($m->{value});
$m->brsft($zeros, 10) if $zeros != 0;
$m;
}
sub parts {
# return a copy of both the exponent and the mantissa
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
($x->mantissa(), $x->exponent());
}
sub sparts {
my $self = shift;
my $class = ref $self;
croak("sparts() is an instance method, not a class method")
unless $class;
# Not-a-number.
if ($self -> is_nan()) {
my $mant = $self -> copy(); # mantissa
return $mant unless wantarray; # scalar context
my $expo = $class -> bnan(); # exponent
return ($mant, $expo); # list context
}
# Infinity.
if ($self -> is_inf()) {
my $mant = $self -> copy(); # mantissa
return $mant unless wantarray; # scalar context
my $expo = $class -> binf('+'); # exponent
return ($mant, $expo); # list context
}
# Finite number.
my $mant = $self -> copy();
my $nzeros = $LIB -> _zeros($mant -> {value});
$mant -> brsft($nzeros, 10) if $nzeros != 0;
return $mant unless wantarray;
my $expo = $class -> new($nzeros);
return ($mant, $expo);
}
sub nparts {
my $self = shift;
my $class = ref $self;
croak("nparts() is an instance method, not a class method")
unless $class;
# Not-a-number.
if ($self -> is_nan()) {
my $mant = $self -> copy(); # mantissa
return $mant unless wantarray; # scalar context
my $expo = $class -> bnan(); # exponent
return ($mant, $expo); # list context
}
# Infinity.
if ($self -> is_inf()) {
my $mant = $self -> copy(); # mantissa
return $mant unless wantarray; # scalar context
my $expo = $class -> binf('+'); # exponent
return ($mant, $expo); # list context
}
# Finite number.
my ($mant, $expo) = $self -> sparts();
if ($mant -> bcmp(0)) {
my ($ndigtot, $ndigfrac) = $mant -> length();
my $expo10adj = $ndigtot - $ndigfrac - 1;
if ($expo10adj != 0) {
return $upgrade -> new($self) -> nparts() if $upgrade;
$mant -> bnan();
return $mant unless wantarray;
$expo -> badd($expo10adj);
return ($mant, $expo);
}
}
return $mant unless wantarray;
return ($mant, $expo);
}
sub eparts {
my $self = shift;
my $class = ref $self;
croak("eparts() is an instance method, not a class method")
unless $class;
# Not-a-number and Infinity.
return $self -> sparts() if $self -> is_nan() || $self -> is_inf();
# Finite number.
my ($mant, $expo) = $self -> sparts();
if ($mant -> bcmp(0)) {
my $ndigmant = $mant -> length();
$expo -> badd($ndigmant);
# $c is the number of digits that will be in the integer part of the
# final mantissa.
my $c = $expo -> copy() -> bdec() -> bmod(3) -> binc();
$expo -> bsub($c);
if ($ndigmant > $c) {
return $upgrade -> new($self) -> eparts() if $upgrade;
$mant -> bnan();
return $mant unless wantarray;
return ($mant, $expo);
}
$mant -> blsft($c - $ndigmant, 10);
}
return $mant unless wantarray;
return ($mant, $expo);
}
sub dparts {
my $self = shift;
my $class = ref $self;
croak("dparts() is an instance method, not a class method")
unless $class;
my $int = $self -> copy();
return $int unless wantarray;
my $frc = $class -> bzero();
return ($int, $frc);
}
sub fparts {
my $x = shift;
my $class = ref $x;
croak("fparts() is an instance method") unless $class;
return ($x -> copy(),
$x -> is_nan() ? $class -> bnan() : $class -> bone());
}
sub numerator {
my $x = shift;
my $class = ref $x;
croak("numerator() is an instance method") unless $class;
return $x -> copy();
}
sub denominator {
my $x = shift;
my $class = ref $x;
croak("denominator() is an instance method") unless $class;
return $x -> is_nan() ? $class -> bnan() : $class -> bone();
}
###############################################################################
# String conversion methods
###############################################################################
sub bstr {
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
return 'inf'; # +inf
}
my $str = $LIB->_str($x->{value});
return $x->{sign} eq '-' ? "-$str" : $str;
}
# Scientific notation with significand/mantissa as an integer, e.g., "12345" is
# written as "1.2345e+4".
sub bsstr {
my ($class, $x) = ref($_[0]) ? (undef, $_[0]) : objectify(1, @_);
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
return 'inf'; # +inf
}
my ($m, $e) = $x -> parts();
my $str = $LIB->_str($m->{value}) . 'e+' . $LIB->_str($e->{value});
return $x->{sign} eq '-' ? "-$str" : $str;
}
# Normalized notation, e.g., "12345" is written as "12345e+0".
sub bnstr {
my $x = shift;
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
return 'inf'; # +inf
}
return $x -> bstr() if $x -> is_nan() || $x -> is_inf();
my ($mant, $expo) = $x -> parts();
# The "fraction posision" is the position (offset) for the decimal point
# relative to the end of the digit string.
my $fracpos = $mant -> length() - 1;
if ($fracpos == 0) {
my $str = $LIB->_str($mant->{value}) . "e+" . $LIB->_str($expo->{value});
return $x->{sign} eq '-' ? "-$str" : $str;
}
$expo += $fracpos;
my $mantstr = $LIB->_str($mant -> {value});
substr($mantstr, -$fracpos, 0) = '.';
my $str = $mantstr . 'e+' . $LIB->_str($expo -> {value});
return $x->{sign} eq '-' ? "-$str" : $str;
}
# Engineering notation, e.g., "12345" is written as "12.345e+3".
sub bestr {
my $x = shift;
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
return 'inf'; # +inf
}
my ($mant, $expo) = $x -> parts();
my $sign = $mant -> sign();
$mant -> babs();
my $mantstr = $LIB->_str($mant -> {value});
my $mantlen = CORE::length($mantstr);
my $dotidx = 1;
$expo += $mantlen - 1;
my $c = $expo -> copy() -> bmod(3);
$expo -= $c;
$dotidx += $c;
if ($mantlen $dotidx) {
substr($mantstr, $dotidx, 0) = ".";
}
my $str = $mantstr . 'e+' . $LIB->_str($expo -> {value});
return $sign eq "-" ? "-$str" : $str;
}
# Decimal notation, e.g., "12345".
sub bdstr {
my $x = shift;
if ($x->{sign} ne '+' && $x->{sign} ne '-') {
return $x->{sign} unless $x->{sign} eq '+inf'; # -inf, NaN
return 'inf'; # +inf
}
my $str = $LIB->_str($x->{value});
return $x->{sign} eq '-' ? "-$str" : $str;
}
sub to_hex {
# return as hex string, with prefixed 0x
my $x = shift;
$x = __PACKAGE__->new($x) if !ref($x);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
my $hex = $LIB->_to_hex($x->{value});
return $x->{sign} eq '-' ? "-$hex" : $hex;
}
sub to_oct {
# return as octal string, with prefixed 0
my $x = shift;
$x = __PACKAGE__->new($x) if !ref($x);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
my $oct = $LIB->_to_oct($x->{value});
return $x->{sign} eq '-' ? "-$oct" : $oct;
}
sub to_bin {
# return as binary string, with prefixed 0b
my $x = shift;
$x = __PACKAGE__->new($x) if !ref($x);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
my $bin = $LIB->_to_bin($x->{value});
return $x->{sign} eq '-' ? "-$bin" : $bin;
}
sub to_bytes {
# return a byte string
my $x = shift;
$x = __PACKAGE__->new($x) if !ref($x);
croak("to_bytes() requires a finite, non-negative integer")
if $x -> is_neg() || ! $x -> is_int();
croak("to_bytes() requires a newer version of the $LIB library.")
unless $LIB->can('_to_bytes');
return $LIB->_to_bytes($x->{value});
}
sub to_base {
# return a base anything string
my $x = shift;
$x = __PACKAGE__->new($x) if !ref($x);
croak("the value to convert must be a finite, non-negative integer")
if $x -> is_neg() || !$x -> is_int();
my $base = shift;
$base = __PACKAGE__->new($base) unless ref($base);
croak("the base must be a finite integer >= 2")
if $base is_int();
# If no collating sequence is given, pass some of the conversions to
# methods optimized for those cases.
if (! @_) {
return $x -> to_bin() if $base == 2;
return $x -> to_oct() if $base == 8;
return uc $x -> to_hex() if $base == 16;
return $x -> bstr() if $base == 10;
}
croak("to_base() requires a newer version of the $LIB library.")
unless $LIB->can('_to_base');
return $LIB->_to_base($x->{value}, $base -> {value}, @_ ? shift() : ());
}
sub to_base_num {
my $x = shift;
my $class = ref $x;
# return a base anything string
croak("the value to convert must be a finite non-negative integer")
if $x -> is_neg() || !$x -> is_int();
my $base = shift;
$base = $class -> new($base) unless ref $base;
croak("the base must be a finite integer >= 2")
if $base is_int();
croak("to_base() requires a newer version of the $LIB library.")
unless $LIB->can('_to_base');
# Get a reference to an array of library thingies, and replace each element
# with a Math::BigInt object using that thingy.
my $vals = $LIB -> _to_base_num($x->{value}, $base -> {value});
for my $i (0 .. $#$vals) {
my $x = $class -> bzero();
$x -> {value} = $vals -> [$i];
$vals -> [$i] = $x;
}
return $vals;
}
sub as_hex {
# return as hex string, with prefixed 0x
my $x = shift;
$x = __PACKAGE__->new($x) if !ref($x);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
my $hex = $LIB->_as_hex($x->{value});
return $x->{sign} eq '-' ? "-$hex" : $hex;
}
sub as_oct {
# return as octal string, with prefixed 0
my $x = shift;
$x = __PACKAGE__->new($x) if !ref($x);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
my $oct = $LIB->_as_oct($x->{value});
return $x->{sign} eq '-' ? "-$oct" : $oct;
}
sub as_bin {
# return as binary string, with prefixed 0b
my $x = shift;
$x = __PACKAGE__->new($x) if !ref($x);
return $x->bstr() if $x->{sign} !~ /^[+-]$/; # inf, nan etc
my $bin = $LIB->_as_bin($x->{value});
return $x->{sign} eq '-' ? "-$bin" : $bin;
}
*as_bytes = \&to_bytes;
###############################################################################
# Other conversion methods
###############################################################################
sub numify {
# Make a Perl scalar number from a Math::BigInt object.
my $x = shift;
$x = __PACKAGE__->new($x) unless ref $x;
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;
}
my $num = 0 + $LIB->_num($x->{value});
return $x->{sign} eq '-' ? -$num : $num;
}
###############################################################################
# Private methods and functions.
###############################################################################
sub objectify {
# Convert strings and "foreign objects" to the objects we want.
# The first argument, $count, is the number of following arguments that
# objectify() looks at and converts to objects. The first is a classname.
# If the given count is 0, all arguments will be used.
# After the count is read, objectify obtains the name of the class to which
# the following arguments are converted. If the second argument is a
# reference, use the reference type as the class name. Otherwise, if it is
# a string that looks like a class name, use that. Otherwise, use $class.
# Caller: Gives us:
#
# $x->badd(1); => ref x, scalar y
# Class->badd(1, 2); => classname x (scalar), scalar x, scalar y
# Class->badd(Class->(1), 2); => classname x (scalar), ref x, scalar y
# Math::BigInt::badd(1, 2); => scalar x, scalar y
# A shortcut for the common case $x->unary_op(), in which case the argument
# list is (0, $x) or (1, $x).
return (ref($_[1]), $_[1]) if @_ == 2 && ($_[0] || 0) == 1 && ref($_[1]);
# Check the context.
unless (wantarray) {
croak(__PACKAGE__ . "::objectify() needs list context");
}
# Get the number of arguments to objectify.
my $count = shift;
# Initialize the output array.
my @a = @_;
# If the first argument is a reference, use that reference type as our
# class name. Otherwise, if the first argument looks like a class name,
# then use that as our class name. Otherwise, use the default class name.
my $class;
if (ref($a[0])) { # reference?
$class = ref($a[0]);
} elsif ($a[0] =~ /^[A-Z].*::/) { # string with class name?
$class = shift @a;
} else {
$class = __PACKAGE__; # default class name
}
$count ||= @a;
unshift @a, $class;
no strict 'refs';
# What we upgrade to, if anything. Note that we need the whole upgrade
# chain, since there might be multiple levels of upgrading. E.g., class A
# upgrades to class B, which upgrades to class C. Delay getting the chain
# until we actually need it.
my @upg = ();
my $have_upgrade_chain = 0;
# Disable downgrading, because Math::BigFloat -> foo('1.0', '2.0') needs
# floats.
my $down;
if (defined ${"$a[0]::downgrade"}) {
$down = ${"$a[0]::downgrade"};
${"$a[0]::downgrade"} = undef;
}
ARG: for my $i (1 .. $count) {
my $ref = ref $a[$i];
# Perl scalars are fed to the appropriate constructor.
unless ($ref) {
$a[$i] = $a[0] -> new($a[$i]);
next;
}
# If it is an object of the right class, all is fine.
next if $ref -> isa($a[0]);
# Upgrading is OK, so skip further tests if the argument is upgraded,
# but first get the whole upgrade chain if we haven't got it yet.
unless ($have_upgrade_chain) {
my $cls = $class;
my $upg = $cls -> upgrade();
while (defined $upg) {
last if $upg eq $cls;
push @upg, $upg;
$cls = $upg;
$upg = $cls -> upgrade();
}
$have_upgrade_chain = 1;
}
for my $upg (@upg) {
next ARG if $ref -> isa($upg);
}
# See if we can call one of the as_xxx() methods. We don't know whether
# the as_xxx() method returns an object or a scalar, so re-check
# afterwards.
my $recheck = 0;
if ($a[0] -> isa('Math::BigInt')) {
if ($a[$i] -> can('as_int')) {
$a[$i] = $a[$i] -> as_int();
$recheck = 1;
} elsif ($a[$i] -> can('as_number')) {
$a[$i] = $a[$i] -> as_number();
$recheck = 1;
}
}
elsif ($a[0] -> isa('Math::BigFloat')) {
if ($a[$i] -> can('as_float')) {
$a[$i] = $a[$i] -> as_float();
$recheck = $1;
}
}
# If we called one of the as_xxx() methods, recheck.
if ($recheck) {
$ref = ref($a[$i]);
# Perl scalars are fed to the appropriate constructor.
unless ($ref) {
$a[$i] = $a[0] -> new($a[$i]);
next;
}
# If it is an object of the right class, all is fine.
next if $ref -> isa($a[0]);
}
# Last resort.
$a[$i] = $a[0] -> new($a[$i]);
}
# Reset the downgrading.
${"$a[0]::downgrade"} = $down;
return @a;
}
sub import {
my $class = shift;
$IMPORT++; # remember we did import()
my @a; # unrecognized arguments
while (@_) {
my $param = shift;
# Enable overloading of constants.
if ($param eq ':constant') {
overload::constant
integer => sub {
$class -> new(shift);
},
float => sub {
$class -> new(shift);
},
binary => sub {
# E.g., a literal 0377 shall result in an object whose value
# is decimal 255, but new("0377") returns decimal 377.
return $class -> from_oct($_[0]) if $_[0] =~ /^0_*[0-7]/;
$class -> new(shift);
};
next;
}
# Upgrading.
if ($param eq 'upgrade') {
$class -> upgrade(shift);
next;
}
# Downgrading.
if ($param eq 'downgrade') {
$class -> downgrade(shift);
next;
}
# Accuracy.
if ($param eq 'accuracy') {
$class -> accuracy(shift);
next;
}
# Precision.
if ($param eq 'precision') {
$class -> precision(shift);
next;
}
# Rounding mode.
if ($param eq 'round_mode') {
$class -> round_mode(shift);
next;
}
# Backend library.
if ($param =~ /^(lib|try|only)\z/) {
# try => 0 (no warn if unavailable module)
# lib => 1 (warn on fallback)
# only => 2 (die on fallback)
# Get the list of user-specified libraries.
croak "Library argument for import parameter '$param' is missing"
unless @_;
my $libs = shift;
croak "Library argument for import parameter '$param' is undefined"
unless defined($libs);
# Check and clean up the list of user-specified libraries.
my @libs;
for my $lib (split /,/, $libs) {
$lib =~ s/^\s+//;
$lib =~ s/\s+$//;
if ($lib =~ /[^a-zA-Z0-9_:]/) {
carp "Library name '$lib' contains invalid characters";
next;
}
if (! CORE::length $lib) {
carp "Library name is empty";
next;
}
$lib = "Math::BigInt::$lib" if $lib !~ /^Math::BigInt::/i;
# If a library has already been loaded, that is OK only if the
# requested library is identical to the loaded one.
if (defined($LIB)) {
if ($lib ne $LIB) {
#carp "Library '$LIB' has already been loaded, so",
# " ignoring requested library '$lib'";
}
next;
}
push @libs, $lib;
}
next if defined $LIB;
croak "Library list contains no valid libraries" unless @libs;
# Try to load the specified libraries, if any.
for (my $i = 0 ; $i SUPER::import(@a); # need it for subclasses
$class->export_to_level(1, $class, @a); # need it for Math::BigFloat
}
# We might not have loaded any backend library yet, either because the user
# didn't specify any, or because the specified libraries failed to load and
# the user allows the use of a fallback library.
unless (defined $LIB) {
eval "require $DEFAULT_LIB";
if ($@) {
croak "No lib specified, and couldn't load the default",
" lib '$DEFAULT_LIB'";
}
$LIB = $DEFAULT_LIB;
}
# import done
}
sub _split {
# input: num_str; output: undef for invalid or
# (\$mantissa_sign, \$mantissa_value, \$mantissa_fraction,
# \$exp_sign, \$exp_value)
# Internal, take apart a string and return the pieces.
# Strip leading/trailing whitespace, leading zeros, underscore and reject
# invalid input.
my $x = shift;
# strip white space at front, also extraneous leading zeros
$x =~ s/^\s*([-]?)0*([0-9])/$1$2/g; # will not strip ' .2'
$x =~ s/^\s+//; # but this will
$x =~ s/\s+$//g; # strip white space at end
# shortcut, if nothing to split, return early
if ($x =~ /^[+-]?[0-9]+\z/) {
$x =~ s/^([+-])0*([0-9])/$2/;
my $sign = $1 || '+';
return (\$sign, \$x, \'', \'', \0);
}
# invalid starting char?
return if $x !~ /^[+-]?(\.?[0-9]|0b[0-1]|0x[0-9a-fA-F])/;
return Math::BigInt->from_hex($x) if $x =~ /^[+-]?0x/; # hex string
return Math::BigInt->from_bin($x) if $x =~ /^[+-]?0b/; # binary string
# strip underscores between digits
$x =~ s/([0-9])_([0-9])/$1$2/g;
$x =~ s/([0-9])_([0-9])/$1$2/g; # do twice for 1_2_3
# some possible inputs:
# 2.1234 # 0.12 # 1 # 1E1 # 2.134E1 # 434E-10 # 1.02009E-2
# .2 # 1_2_3.4_5_6 # 1.4E1_2_3 # 1e3 # +.2 # 0e999
my ($m, $e, $last) = split /[Ee]/, $x;
return if defined $last; # last defined => 1e2E3 or others
$e = '0' if !defined $e || $e eq "";
# sign, value for exponent, mantint, mantfrac
my ($es, $ev, $mis, $miv, $mfv);
# valid exponent?
if ($e =~ /^([+-]?)0*([0-9]+)$/) # strip leading zeros
{
$es = $1;
$ev = $2;
# valid mantissa?
return if $m eq '.' || $m eq '';
my ($mi, $mf, $lastf) = split /\./, $m;
return if defined $lastf; # lastf defined => 1.2.3 or others
$mi = '0' if !defined $mi;
$mi .= '0' if $mi =~ /^[\-\+]?$/;
$mf = '0' if !defined $mf || $mf eq '';
if ($mi =~ /^([+-]?)0*([0-9]+)$/) # strip leading zeros
{
$mis = $1 || '+';
$miv = $2;
return unless ($mf =~ /^([0-9]*?)0*$/); # strip trailing zeros
$mfv = $1;
# handle the 0e999 case here
$ev = 0 if $miv eq '0' && $mfv eq '';
return (\$mis, \$miv, \$mfv, \$es, \$ev);
}
}
return; # NaN, not a number
}
sub _e_add {
# Internal helper sub to take two positive integers and their signs and
# then add them. Input ($LIB, $LIB, ('+'|'-'), ('+'|'-')), output
# ($LIB, ('+'|'-')).
my ($x, $y, $xs, $ys) = @_;
# if the signs are equal we can add them (-5 + -3 => -(5 + 3) => -8)
if ($xs eq $ys) {
$x = $LIB->_add($x, $y); # +a + +b or -a + -b
} else {
my $a = $LIB->_acmp($x, $y);
if ($a == 0) {
# This does NOT modify $x in-place. TODO: Fix this?
$x = $LIB->_zero(); # result is 0
$xs = '+';
return ($x, $xs);
}
if ($a > 0) {
$x = $LIB->_sub($x, $y); # abs sub
} else { # a _sub ($y, $x, 1); # abs sub
$xs = $ys;
}
}
$xs = '+' if $xs eq '-' && $LIB->_is_zero($x); # no "-0"
return ($x, $xs);
}
sub _e_sub {
# Internal helper sub to take two positive integers and their signs and
# then subtract them. Input ($LIB, $LIB, ('+'|'-'), ('+'|'-')),
# output ($LIB, ('+'|'-'))
my ($x, $y, $xs, $ys) = @_;
# flip sign
$ys = $ys eq '+' ? '-' : '+'; # swap sign of second operand ...
_e_add($x, $y, $xs, $ys); # ... and let _e_add() do the job
#$LIB -> _sadd($x, $xs, $y, $ys); # ... and let $LIB -> _sadd() do the job
}
sub _trailing_zeros {
# return the amount of trailing zeros in $x (as scalar)
my $x = shift;
$x = __PACKAGE__->new($x) unless ref $x;
return 0 if $x->{sign} !~ /^[+-]$/; # NaN, inf, -inf etc
$LIB->_zeros($x->{value}); # must handle odd values, 0 etc
}
sub _scan_for_nonzero {
# internal, used by bround() to scan for non-zeros after a '5'
my ($x, $pad, $xs, $len) = @_;
return 0 if $len == 1; # "5" is trailed by invisible zeros
my $follow = $pad - 1;
return 0 if $follow > $len || $follow can('numify') ? $a->numify() : "$a" if defined $a && ref($a);
$p = $p->can('numify') ? $p->numify() : "$p" if defined $p && ref($p);
# now pick $a or $p, but only if we have got "arguments"
if (!defined $a) {
foreach ($self, @args) {
# take the defined one, or if both defined, the one that is smaller
$a = $_->{_a} if (defined $_->{_a}) && (!defined $a || $_->{_a} -3, and 3 > 2
$p = $_->{_p} if (defined $_->{_p}) && (!defined $p || $_->{_p} > $p);
}
}
# if still none defined, use globals (#2)
$a = ${"$class\::accuracy"} unless defined $a;
$p = ${"$class\::precision"} unless defined $p;
# A == 0 is useless, so undef it to signal no rounding
$a = undef if defined $a && $a == 0;
# no rounding today?
return ($self) unless defined $a || defined $p; # early out
# set A and set P is an fatal error
return ($self->bnan()) if defined $a && defined $p; # error
$r = ${"$class\::round_mode"} unless defined $r;
if ($r !~ /^(even|odd|[+-]inf|zero|trunc|common)$/) {
croak("Unknown round mode '$r'");
}
$a = int($a) if defined $a;
$p = int($p) if defined $p;
($self, $a, $p, $r);
}
# Trims the sign of the significand, the (absolute value of the) significand,
# the sign of the exponent, and the (absolute value of the) exponent. The
# returned values have no underscores ("_") or unnecessary leading or trailing
# zeros.
sub _trim_split_parts {
shift;
my $sig_sgn = shift() || '+';
my $sig_str = shift() || '0';
my $exp_sgn = shift() || '+';
my $exp_str = shift() || '0';
$sig_str =~ tr/_//d; # "1.0_0_0" -> "1.000"
$sig_str =~ s/^0+//; # "01.000" -> "1.000"
$sig_str =~ s/\.0*$// # "1.000" -> "1"
|| $sig_str =~ s/(\..*[^0])0+$/$1/; # "1.010" -> "1.01"
$sig_str = '0' unless CORE::length($sig_str);
return '+', '0', '+', '0' if $sig_str eq '0';
$exp_str =~ tr/_//d; # "01_234" -> "01234"
$exp_str =~ s/^0+//; # "01234" -> "1234"
$exp_str = '0' unless CORE::length($exp_str);
return $sig_sgn, $sig_str, $exp_sgn, $exp_str;
}
# Takes any string representing a valid decimal number and splits it into four
# strings: the sign of the significand, the absolute value of the significand,
# the sign of the exponent, and the absolute value of the exponent. Both the
# significand and the exponent are in base 10.
#
# Perl accepts literals like the following. The value is 100.1.
#
# 1__0__.__0__1__e+0__1__ (prints "Misplaced _ in number")
# 1_0.0_1e+0_1
#
# Strings representing decimal numbers do not allow underscores, so only the
# following is valid
#
# "10.01e+01"
sub _dec_str_to_str_parts {
my $class = shift;
my $str = shift;
if ($str =~ /
^
# optional leading whitespace
\s*
# optional sign
( [+-]? )
# significand
(
# integer part and optional fraction part ...
\d+ (?: _+ \d+ )* _*
(?:
\.
(?: _* \d+ (?: _+ \d+ )* _* )?
)?
|
# ... or mandatory fraction part
\.
\d+ (?: _+ \d+ )* _*
)
# optional exponent
(?:
[Ee]
( [+-]? )
( \d+ (?: _+ \d+ )* _* )
)?
# optional trailing whitespace
\s*
$
/x)
{
return $class -> _trim_split_parts($1, $2, $3, $4);
}
return;
}
# Takes any string representing a valid hexadecimal number and splits it into
# four strings: the sign of the significand, the absolute value of the
# significand, the sign of the exponent, and the absolute value of the exponent.
# The significand is in base 16, and the exponent is in base 2.
#
# Perl accepts literals like the following. The "x" might be a capital "X". The
# value is 32.0078125.
#
# 0x__1__0__.0__1__p+0__1__ (prints "Misplaced _ in number")
# 0x1_0.0_1p+0_1
#
# The CORE::hex() function does not accept floating point accepts
#
# "0x_1_0"
# "x_1_0"
# "_1_0"
sub _hex_str_to_str_parts {
my $class = shift;
my $str = shift;
if ($str =~ /
^
# optional leading whitespace
\s*
# optional sign
( [+-]? )
# optional hex prefix
(?: 0? [Xx] _* )?
# significand using the hex digits 0..9 and a..f
(
# integer part and optional fraction part ...
[0-9a-fA-F]+ (?: _+ [0-9a-fA-F]+ )* _*
(?:
\.
(?: _* [0-9a-fA-F]+ (?: _+ [0-9a-fA-F]+ )* _* )?
)?
|
# ... or mandatory fraction part
\.
[0-9a-fA-F]+ (?: _+ [0-9a-fA-F]+ )* _*
)
# optional exponent (power of 2) using decimal digits
(?:
[Pp]
( [+-]? )
( \d+ (?: _+ \d+ )* _* )
)?
# optional trailing whitespace
\s*
$
/x)
{
return $class -> _trim_split_parts($1, $2, $3, $4);
}
return;
}
# Takes any string representing a valid octal number and splits it into four
# strings: the sign of the significand, the absolute value of the significand,
# the sign of the exponent, and the absolute value of the exponent. The
# significand is in base 8, and the exponent is in base 2.
sub _oct_str_to_str_parts {
my $class = shift;
my $str = shift;
if ($str =~ /
^
# optional leading whitespace
\s*
# optional sign
( [+-]? )
# optional octal prefix
(?: 0? [Oo] _* )?
# significand using the octal digits 0..7
(
# integer part and optional fraction part ...
[0-7]+ (?: _+ [0-7]+ )* _*
(?:
\.
(?: _* [0-7]+ (?: _+ [0-7]+ )* _* )?
)?
|
# ... or mandatory fraction part
\.
[0-7]+ (?: _+ [0-7]+ )* _*
)
# optional exponent (power of 2) using decimal digits
(?:
[Pp]
( [+-]? )
( \d+ (?: _+ \d+ )* _* )
)?
# optional trailing whitespace
\s*
$
/x)
{
return $class -> _trim_split_parts($1, $2, $3, $4);
}
return;
}
# Takes any string representing a valid binary number and splits it into four
# strings: the sign of the significand, the absolute value of the significand,
# the sign of the exponent, and the absolute value of the exponent. The
# significand is in base 2, and the exponent is in base 2.
sub _bin_str_to_str_parts {
my $class = shift;
my $str = shift;
if ($str =~ /
^
# optional leading whitespace
\s*
# optional sign
( [+-]? )
# optional binary prefix
(?: 0? [Bb] _* )?
# significand using the binary digits 0 and 1
(
# integer part and optional fraction part ...
[01]+ (?: _+ [01]+ )* _*
(?:
\.
(?: _* [01]+ (?: _+ [01]+ )* _* )?
)?
|
# ... or mandatory fraction part
\.
[01]+ (?: _+ [01]+ )* _*
)
# optional exponent (power of 2) using decimal digits
(?:
[Pp]
( [+-]? )
( \d+ (?: _+ \d+ )* _* )
)?
# optional trailing whitespace
\s*
$
/x)
{
return $class -> _trim_split_parts($1, $2, $3, $4);
}
return;
}
# Takes any string representing a valid decimal number and splits it into four
# parts: the sign of the significand, the absolute value of the significand as a
# libray thingy, the sign of the exponent, and the absolute value of the
# exponent as a library thingy.
sub _dec_parts_to_lib_parts {
shift;
my ($sig_sgn, $sig_str, $exp_sgn, $exp_str) = @_;
# Handle zero.
if ($sig_str eq '0') {
return '+', $LIB -> _zero(), '+', $LIB -> _zero();
}
# Absolute value of exponent as library "object".
my $exp_lib = $LIB -> _new($exp_str);
# If there is a dot in the significand, remove it so the significand
# becomes an integer and adjust the exponent accordingly. Also remove
# leading zeros which might now appear in the significand. E.g.,
#
# 12.345e-2 -> 12345e-5
# 12.345e+2 -> 12345e-1
# 0.0123e+5 -> 00123e+1 -> 123e+1
my $idx = index $sig_str, '.';
if ($idx >= 0) {
substr($sig_str, $idx, 1) = '';
# delta = length - index
my $delta = $LIB -> _new(CORE::length($sig_str));
$delta = $LIB -> _sub($delta, $LIB -> _new($idx));
# exponent - delta
($exp_lib, $exp_sgn) = _e_sub($exp_lib, $delta, $exp_sgn, '+');
#($exp_lib, $exp_sgn) = $LIB -> _ssub($exp_lib, $exp_sgn, $delta, '+');
$sig_str =~ s/^0+//;
}
# If there are trailing zeros in the significand, remove them and
# adjust the exponent. E.g.,
#
# 12340e-5 -> 1234e-4
# 12340e-1 -> 1234e0
# 12340e+3 -> 1234e4
if ($sig_str =~ s/(0+)\z//) {
my $len = CORE::length($1);
($exp_lib, $exp_sgn) =
$LIB -> _sadd($exp_lib, $exp_sgn, $LIB -> _new($len), '+');
}
# At this point, the significand is empty or an integer with no trailing
# zeros. The exponent is in base 10.
unless (CORE::length $sig_str) {
return '+', $LIB -> _zero(), '+', $LIB -> _zero();
}
# Absolute value of significand as library "object".
my $sig_lib = $LIB -> _new($sig_str);
return $sig_sgn, $sig_lib, $exp_sgn, $exp_lib;
}
# Takes any string representing a valid binary number and splits it into four
# parts: the sign of the significand, the absolute value of the significand as a
# libray thingy, the sign of the exponent, and the absolute value of the
# exponent as a library thingy.
sub _bin_parts_to_lib_parts {
shift;
my ($sig_sgn, $sig_str, $exp_sgn, $exp_str, $bpc) = @_;
my $bpc_lib = $LIB -> _new($bpc);
# Handle zero.
if ($sig_str eq '0') {
return '+', $LIB -> _zero(), '+', $LIB -> _zero();
}
# Absolute value of exponent as library "object".
my $exp_lib = $LIB -> _new($exp_str);
# If there is a dot in the significand, remove it so the significand
# becomes an integer and adjust the exponent accordingly. Also remove
# leading zeros which might now appear in the significand. E.g., with
# hexadecimal numbers
#
# 12.345p-2 -> 12345p-14
# 12.345p+2 -> 12345p-10
# 0.0123p+5 -> 00123p-11 -> 123p-11
my $idx = index $sig_str, '.';
if ($idx >= 0) {
substr($sig_str, $idx, 1) = '';
# delta = (length - index) * bpc
my $delta = $LIB -> _new(CORE::length($sig_str));
$delta = $LIB -> _sub($delta, $LIB -> _new($idx));
$delta = $LIB -> _mul($delta, $bpc_lib) if $bpc != 1;
# exponent - delta
($exp_lib, $exp_sgn) = _e_sub($exp_lib, $delta, $exp_sgn, '+');
#($exp_lib, $exp_sgn) = $LIB -> _ssub($exp_lib, $exp_sgn, $delta, '+');
$sig_str =~ s/^0+//;
}
# If there are trailing zeros in the significand, remove them and
# adjust the exponent accordingly. E.g., with hexadecimal numbers
#
# 12340p-5 -> 1234p-1
# 12340p-1 -> 1234p+3
# 12340p+3 -> 1234p+7
if ($sig_str =~ s/(0+)\z//) {
# delta = length * bpc
my $delta = $LIB -> _new(CORE::length($1));
$delta = $LIB -> _mul($delta, $bpc_lib) if $bpc != 1;
# exponent + delta
($exp_lib, $exp_sgn) = $LIB -> _sadd($exp_lib, $exp_sgn, $delta, '+');
}
# At this point, the significand is empty or an integer with no leading
# or trailing zeros. The exponent is in base 2.
unless (CORE::length $sig_str) {
return '+', $LIB -> _zero(), '+', $LIB -> _zero();
}
# Absolute value of significand as library "object".
my $sig_lib = $bpc == 1 ? $LIB -> _from_bin('0b' . $sig_str)
: $bpc == 3 ? $LIB -> _from_oct('0' . $sig_str)
: $bpc == 4 ? $LIB -> _from_hex('0x' . $sig_str)
: die "internal error: invalid exponent multiplier";
# If the exponent (in base 2) is positive or zero ...
if ($exp_sgn eq '+') {
if (!$LIB -> _is_zero($exp_lib)) {
# Multiply significand by 2 raised to the exponent.
my $p = $LIB -> _pow($LIB -> _two(), $exp_lib);
$sig_lib = $LIB -> _mul($sig_lib, $p);
$exp_lib = $LIB -> _zero();
}
}
# ... else if the exponent is negative ...
else {
# Rather than dividing the significand by 2 raised to the absolute
# value of the exponent, multiply the significand by 5 raised to the
# absolute value of the exponent and let the exponent be in base 10:
#
# a * 2^(-b) = a * 5^b * 10^(-b) = c * 10^(-b), where c = a * 5^b
my $p = $LIB -> _pow($LIB -> _new("5"), $exp_lib);
$sig_lib = $LIB -> _mul($sig_lib, $p);
}
# Adjust for the case when the conversion to decimal introduced trailing
# zeros in the significand.
my $n = $LIB -> _zeros($sig_lib);
if ($n) {
$n = $LIB -> _new($n);
$sig_lib = $LIB -> _rsft($sig_lib, $n, 10);
($exp_lib, $exp_sgn) = $LIB -> _sadd($exp_lib, $exp_sgn, $n, '+');
}
return $sig_sgn, $sig_lib, $exp_sgn, $exp_lib;
}
# Takes any string representing a valid hexadecimal number and splits it into
# four parts: the sign of the significand, the absolute value of the significand
# as a libray thingy, the sign of the exponent, and the absolute value of the
# exponent as a library thingy.
sub _hex_str_to_lib_parts {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _hex_str_to_str_parts($str)) {
return $class -> _bin_parts_to_lib_parts(@parts, 4); # 4 bits pr. chr
}
return;
}
# Takes any string representing a valid octal number and splits it into four
# parts: the sign of the significand, the absolute value of the significand as a
# libray thingy, the sign of the exponent, and the absolute value of the
# exponent as a library thingy.
sub _oct_str_to_lib_parts {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _oct_str_to_str_parts($str)) {
return $class -> _bin_parts_to_lib_parts(@parts, 3); # 3 bits pr. chr
}
return;
}
# Takes any string representing a valid binary number and splits it into four
# parts: the sign of the significand, the absolute value of the significand as a
# libray thingy, the sign of the exponent, and the absolute value of the
# exponent as a library thingy.
sub _bin_str_to_lib_parts {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _bin_str_to_str_parts($str)) {
return $class -> _bin_parts_to_lib_parts(@parts, 1); # 1 bit pr. chr
}
return;
}
# Decimal string is split into the sign of the signficant, the absolute value of
# the significand as library thingy, the sign of the exponent, and the absolute
# value of the exponent as a a library thingy.
sub _dec_str_to_lib_parts {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _dec_str_to_str_parts($str)) {
return $class -> _dec_parts_to_lib_parts(@parts);
}
return;
}
# Hexdecimal string to a string using decimal floating point notation.
sub hex_str_to_dec_flt_str {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _hex_str_to_lib_parts($str)) {
return $class -> _lib_parts_to_flt_str(@parts);
}
return;
}
# Octal string to a string using decimal floating point notation.
sub oct_str_to_dec_flt_str {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _oct_str_to_lib_parts($str)) {
return $class -> _lib_parts_to_flt_str(@parts);
}
return;
}
# Binary string to a string decimal floating point notation.
sub bin_str_to_dec_flt_str {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _bin_str_to_lib_parts($str)) {
return $class -> _lib_parts_to_flt_str(@parts);
}
return;
}
# Decimal string to a string using decimal floating point notation.
sub dec_str_to_dec_flt_str {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _dec_str_to_lib_parts($str)) {
return $class -> _lib_parts_to_flt_str(@parts);
}
return;
}
# Hexdecimal string to decimal notation (no exponent).
sub hex_str_to_dec_str {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _dec_str_to_lib_parts($str)) {
return $class -> _lib_parts_to_dec_str(@parts);
}
return;
}
# Octal string to decimal notation (no exponent).
sub oct_str_to_dec_str {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _oct_str_to_lib_parts($str)) {
return $class -> _lib_parts_to_dec_str(@parts);
}
return;
}
# Binary string to decimal notation (no exponent).
sub bin_str_to_dec_str {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _bin_str_to_lib_parts($str)) {
return $class -> _lib_parts_to_dec_str(@parts);
}
return;
}
# Decimal string to decimal notation (no exponent).
sub dec_str_to_dec_str {
my $class = shift;
my $str = shift;
if (my @parts = $class -> _dec_str_to_lib_parts($str)) {
return $class -> _lib_parts_to_dec_str(@parts);
}
return;
}
sub _lib_parts_to_flt_str {
my $class = shift;
my @parts = @_;
return $parts[0] . $LIB -> _str($parts[1])
. 'e' . $parts[2] . $LIB -> _str($parts[3]);
}
sub _lib_parts_to_dec_str {
my $class = shift;
my @parts = @_;
# The number is an integer iff the exponent is non-negative.
if ($parts[2] eq '+') {
my $str = $parts[0]
. $LIB -> _str($LIB -> _lsft($parts[1], $parts[3], 10));
return $str;
}
# If it is not an integer, add a decimal point.
else {
my $mant = $LIB -> _str($parts[1]);
my $mant_len = CORE::length($mant);
my $expo = $LIB -> _num($parts[3]);
my $len_cmp = $mant_len $expo;
if ($len_cmp section!)
# to warn if Math::BigInt::GMP cannot be found, use
use Math::BigInt lib => 'GMP';
# to suppress the warning if Math::BigInt::GMP cannot be found, use
# use Math::BigInt try => 'GMP';
# to die if Math::BigInt::GMP cannot be found, use
# use Math::BigInt only => 'GMP';
my $str = '1234567890';
my @values = (64, 74, 18);
my $n = 1; my $sign = '-';
# Configuration methods (may be used as class methods and instance methods)
Math::BigInt->accuracy(); # get class accuracy
Math::BigInt->accuracy($n); # set class accuracy
Math::BigInt->precision(); # get class precision
Math::BigInt->precision($n); # set class precision
Math::BigInt->round_mode(); # get class rounding mode
Math::BigInt->round_mode($m); # set global round mode, must be one of
# 'even', 'odd', '+inf', '-inf', 'zero',
# 'trunc', or 'common'
Math::BigInt->config(); # return hash with configuration
# Constructor methods (when the class methods below are used as instance
# methods, the value is assigned the invocand)
$x = Math::BigInt->new($str); # defaults to 0
$x = Math::BigInt->new('0x123'); # from hexadecimal
$x = Math::BigInt->new('0b101'); # from binary
$x = Math::BigInt->from_hex('cafe'); # from hexadecimal
$x = Math::BigInt->from_oct('377'); # from octal
$x = Math::BigInt->from_bin('1101'); # from binary
$x = Math::BigInt->from_base('why', 36); # from any base
$x = Math::BigInt->from_base_num([1, 0], 2); # from any base
$x = Math::BigInt->bzero(); # create a +0
$x = Math::BigInt->bone(); # create a +1
$x = Math::BigInt->bone('-'); # create a -1
$x = Math::BigInt->binf(); # create a +inf
$x = Math::BigInt->binf('-'); # create a -inf
$x = Math::BigInt->bnan(); # create a Not-A-Number
$x = Math::BigInt->bpi(); # returns pi
$y = $x->copy(); # make a copy (unlike $y = $x)
$y = $x->as_int(); # return as a Math::BigInt
# Boolean methods (these don't modify the invocand)
$x->is_zero(); # if $x is 0
$x->is_one(); # if $x is +1
$x->is_one("+"); # ditto
$x->is_one("-"); # if $x is -1
$x->is_inf(); # if $x is +inf or -inf
$x->is_inf("+"); # if $x is +inf
$x->is_inf("-"); # if $x is -inf
$x->is_nan(); # if $x is NaN
$x->is_positive(); # if $x > 0
$x->is_pos(); # ditto
$x->is_negative(); # if $x is_neg(); # ditto
$x->is_odd(); # if $x is odd
$x->is_even(); # if $x is even
$x->is_int(); # if $x is an integer
# Comparison methods
$x->bcmp($y); # compare numbers (undef, 0)
$x->bacmp($y); # compare absolutely (undef, 0)
$x->beq($y); # true if and only if $x == $y
$x->bne($y); # true if and only if $x != $y
$x->blt($y); # true if and only if $x ble($y); # true if and only if $x bgt($y); # true if and only if $x > $y
$x->bge($y); # true if and only if $x >= $y
# Arithmetic methods
$x->bneg(); # negation
$x->babs(); # absolute value
$x->bsgn(); # sign function (-1, 0, 1, or NaN)
$x->bnorm(); # normalize (no-op)
$x->binc(); # increment $x by 1
$x->bdec(); # decrement $x by 1
$x->badd($y); # addition (add $y to $x)
$x->bsub($y); # subtraction (subtract $y from $x)
$x->bmul($y); # multiplication (multiply $x by $y)
$x->bmuladd($y,$z); # $x = $x * $y + $z
$x->bdiv($y); # division (floored), set $x to quotient
# return (quo,rem) or quo if scalar
$x->btdiv($y); # division (truncated), set $x to quotient
# return (quo,rem) or quo if scalar
$x->bmod($y); # modulus (x % y)
$x->btmod($y); # modulus (truncated)
$x->bmodinv($mod); # modular multiplicative inverse
$x->bmodpow($y,$mod); # modular exponentiation (($x ** $y) % $mod)
$x->bpow($y); # power of arguments (x ** y)
$x->blog(); # logarithm of $x to base e (Euler's number)
$x->blog($base); # logarithm of $x to base $base (e.g., base 2)
$x->bexp(); # calculate e ** $x where e is Euler's number
$x->bnok($y); # x over y (binomial coefficient n over k)
$x->buparrow($n, $y); # Knuth's up-arrow notation
$x->backermann($y); # the Ackermann function
$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->blsft($n); # left shift $n places in base 2
$x->blsft($n,$b); # left shift $n places in base $b
# returns (quo,rem) or quo (scalar context)
$x->brsft($n); # right shift $n places in base 2
$x->brsft($n,$b); # right shift $n places in base $b
# returns (quo,rem) or quo (scalar context)
# Bitwise methods
$x->band($y); # bitwise and
$x->bior($y); # bitwise inclusive or
$x->bxor($y); # bitwise exclusive or
$x->bnot(); # bitwise not (two's complement)
# Rounding methods
$x->round($A,$P,$mode); # round to accuracy or precision using
# rounding mode $mode
$x->bround($n); # accuracy: preserve $n digits
$x->bfround($n); # $n > 0: round to $nth digit left of dec. point
# $n bfloor(); # round towards minus infinity
$x->bceil(); # round towards plus infinity
$x->bint(); # round towards zero
# Other mathematical methods
$x->bgcd($y); # greatest common divisor
$x->blcm($y); # least common multiple
# Object property methods (do not modify the invocand)
$x->sign(); # the sign, either +, - or NaN
$x->digit($n); # the nth digit, counting from the right
$x->digit(-$n); # the nth digit, counting from the left
$x->length(); # return number of digits in number
($xl,$f) = $x->length(); # length of number and length of fraction
# part, latter is always 0 digits long
# for Math::BigInt objects
$x->mantissa(); # return (signed) mantissa as a Math::BigInt
$x->exponent(); # return exponent as a Math::BigInt
$x->parts(); # return (mantissa,exponent) as a Math::BigInt
$x->sparts(); # mantissa and exponent (as integers)
$x->nparts(); # mantissa and exponent (normalised)
$x->eparts(); # mantissa and exponent (engineering notation)
$x->dparts(); # integer and fraction part
$x->fparts(); # numerator and denominator
$x->numerator(); # numerator
$x->denominator(); # denominator
# Conversion methods (do not modify the invocand)
$x->bstr(); # decimal notation, possibly zero padded
$x->bsstr(); # string in scientific notation with integers
$x->bnstr(); # string in normalized notation
$x->bestr(); # string in engineering notation
$x->bdstr(); # string in decimal notation
$x->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_base($b); # as string in any base
$x->to_base_num($b); # as array of integers in any base
$x->as_hex(); # as signed hexadecimal string with prefixed 0x
$x->as_bin(); # as signed binary string with prefixed 0b
$x->as_oct(); # as signed octal string with prefixed 0
# Other conversion methods
$x->numify(); # return as scalar (might overflow or underflow)
=head1 DESCRIPTION
Math::BigInt provides support for arbitrary precision integers. Overloading is
also provided for Perl operators.
=head2 Input
Input values to these routines may be any scalar number or string that looks
like a number and represents an integer. Anything that is accepted by Perl as a
literal numeric constant should be accepted by this module, except that finite
non-integers return NaN.
=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, or does not represent a finite integer,
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
Input given as scalar numbers might lose precision. Quote your input to ensure
that no digits are lost:
$x = Math::BigInt->new( 56789012345678901234 ); # bad
$x = Math::BigInt->new('56789012345678901234'); # good
Currently, C<:bigint->new()> (no input argument) and
C<:bigint->new("")> return 0. This might change in the future, so always
use the following explicit forms to get a zero:
$zero = Math::BigInt->bzero();
=head2 Output
Output values are usually Math::BigInt objects.
Boolean operators C