my $class = "Math::BigInt";
use 5.006002;
-$VERSION = '1.80';
+$VERSION = '1.87';
@ISA = qw(Exporter);
@EXPORT_OK = qw(objectify bgcd blcm);
"$_[1]" cmp $_[0]->bstr() :
$_[0]->bstr() cmp "$_[1]" },
-# make cos()/sin()/exp() "work" with BigInt's or subclasses
+# make cos()/sin()/atan2() "work" with BigInt's or subclasses
'cos' => sub { cos($_[0]->numify()) },
'sin' => sub { sin($_[0]->numify()) },
-'exp' => sub { exp($_[0]->numify()) },
'atan2' => sub { $_[2] ?
atan2($_[1],$_[0]->numify()) :
atan2($_[0]->numify(),$_[1]) },
# log(N) is log(N, e), where e is Euler's number
'log' => sub { $_[0]->copy()->blog($_[1], undef); },
+'exp' => sub { $_[0]->copy()->bexp($_[1]); },
'int' => sub { $_[0]->copy(); },
'neg' => sub { $_[0]->copy()->bneg(); },
'abs' => sub { $_[0]->copy()->babs(); },
my $class = shift || 'Math::BigInt';
no strict 'refs';
- if (@_ > 0)
+ if (@_ > 1 || (@_ == 1 && (ref($_[0]) eq 'HASH')))
{
# try to set given options as arguments from hash
{
$cfg->{$key} = ${"${class}::$key"};
};
+ if (@_ == 1 && (ref($_[0]) ne 'HASH'))
+ {
+ # calls of the style config('lib') return just this value
+ return $cfg->{$_[0]};
+ }
$cfg;
}
my $c = ref($self); # find out class of argument(s)
no strict 'refs';
+ # convert to normal scalar for speed and correctness in inner parts
+ $a = $a->numify() if defined $a && ref($a);
+ $p = $p->numify() if defined $a && ref($p);
+
# now pick $a or $p, but only if we have got "arguments"
if (!defined $a)
{
# set up parameters
my ($self,$x,$y,@r) = (ref($_[0]),@_);
+
# objectify is costly, so avoid it
if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
{
return $x if $x->modify('blog');
+ $base = $self->new($base) if defined $base && !ref $base;
+
# inf, -inf, NaN, <0 => NaN
return $x->bnan()
if $x->{sign} ne '+' || (defined $base && $base->{sign} ne '+');
$x->round(@r);
}
+sub bnok
+ {
+ # Calculate n over k (binomial coefficient or "choose" function) as integer.
+ # set up parameters
+ my ($self,$x,$y,@r) = (ref($_[0]),@_);
+
+ # objectify is costly, so avoid it
+ if ((!ref($_[0])) || (ref($_[0]) ne ref($_[1])))
+ {
+ ($self,$x,$y,@r) = objectify(2,@_);
+ }
+
+ return $x if $x->modify('bnok');
+ return $x->bnan() if $x->{sign} eq 'NaN' || $y->{sign} eq 'NaN';
+ return $x->binf() if $x->{sign} eq '+inf';
+
+ # k > n or k < 0 => 0
+ my $cmp = $x->bacmp($y);
+ return $x->bzero() if $cmp < 0 || $y->{sign} =~ /^-/;
+ # k == n => 1
+ return $x->bone(@r) if $cmp == 0;
+
+ if ($CALC->can('_nok'))
+ {
+ $x->{value} = $CALC->_nok($x->{value},$y->{value});
+ }
+ else
+ {
+ # ( 7 ) 7! 7*6*5 * 4*3*2*1 7 * 6 * 5
+ # ( - ) = --------- = --------------- = ---------
+ # ( 3 ) 3! (7-3)! 3*2*1 * 4*3*2*1 3 * 2 * 1
+
+ # compute n - k + 2 (so we start with 5 in the example above)
+ my $z = $x - $y;
+ if (!$z->is_one())
+ {
+ $z->binc();
+ my $r = $z->copy(); $z->binc();
+ my $d = $self->new(2);
+ while ($z->bacmp($x) <= 0) # f < x ?
+ {
+ $r->bmul($z); $r->bdiv($d);
+ $z->binc(); $d->binc();
+ }
+ $x->{value} = $r->{value}; $x->{sign} = '+';
+ }
+ else { $x->bone(); }
+ }
+ $x->round(@r);
+ }
+
+sub bexp
+ {
+ # Calculate e ** $x (Euler's number to the power of X), truncated to
+ # an integer value.
+ my ($self,$x,@r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_);
+ return $x if $x->modify('bexp');
+
+ # inf, -inf, NaN, <0 => 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)
+ {
+ $u = $u->as_int();
+ # modify $x in place
+ $x->{value} = $u->{value};
+ $x->round(@r);
+ }
+ else { $x = $u; }
+ }
+
sub blcm
{
# (BINT or num_str, BINT or num_str) return BINT
}
return $self->bone() if $x->is_zero();
- $self->new($x->_trailing_zeros());
+ # 12300 => 2 trailing zeros => exponent is 2
+ $self->new( $CALC->_zeros($x->{value}) );
}
sub mantissa
return $self->new($x->{sign});
}
my $m = $x->copy(); delete $m->{_p}; delete $m->{_a};
+
# that's a bit inefficient:
- my $zeros = $m->_trailing_zeros();
+ my $zeros = $CALC->_zeros($m->{value});
$m->brsft($zeros,10) if $zeros != 0;
$m;
}
}
my $up = ${"$a[0]::upgrade"};
- #print "Now in objectify, my class is today $a[0], count = $count\n";
+ # print STDERR "# Now in objectify, my class is today $a[0], count = $count\n";
if ($count == 0)
{
while (@_)
while ($count > 0)
{
$count--;
- $k = shift;
+ $k = shift;
if (!ref($k))
{
$k = $a[0]->new($k);
$x->bmodinv($mod); # the inverse of $x in the given modulus $mod
$x->bpow($y); # power of arguments (x ** y)
- $x->blsft($y); # left shift in base 10
- $x->brsft($y); # right shift in base 10
+ $x->blsft($y); # left shift in base 2
+ $x->brsft($y); # right shift in base 2
# returns (quo,rem) or quo if in scalar context
$x->blsft($y,$n); # left shift by $y places in base $n
$x->brsft($y,$n); # right shift by $y places in base $n
$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->bnok($y); # x over y (binomial coefficient n over k)
+
+ $x->blog(); # logarithm of $x to base e (Euler's number)
+ $x->blog($base); # logarithm of $x to base $base (f.i. 2)
+ $x->bexp(); # calculate e ** $x where e is Euler's number
+
$x->round($A,$P,$mode); # round to accuracy or precision using mode $mode
$x->bround($n); # accuracy: preserve $n digits
$x->bfround($n); # round to $nth digit, no-op for BigInts
$x->babs();
-Set the number to it's absolute value, e.g. change the sign from '-' to '+'
+Set the number to its absolute value, e.g. change the sign from '-' to '+'
and from '-inf' to '+inf', respectively. Does nothing for NaN or positive
numbers.
$x->bnot();
-Two's complement (bit wise not). This is equivalent to
+Two's complement (bitwise not). This is equivalent to
$x->binc()->bneg();
$x->bpow($y); # power of arguments (x ** y)
+=head2 blog()
+
+ $x->blog($base, $accuracy); # logarithm of x to the base $base
+
+If C<$base> is not defined, Euler's number (e) is used:
+
+ print $x->blog(undef, 100); # log(x) to 100 digits
+
+=head2 bexp()
+
+ $x->bexp($accuracy); # calculate e ** X
+
+Calculates the expression C<e ** $x> where C<e> is Euler's number.
+
+This method was added in v1.82 of Math::BigInt (April 2007).
+
+See also L<blog()>.
+
+=head2 bnok()
+
+ $x->bnok($y); # x over y (binomial coefficient n over k)
+
+Calculates the binomial coefficient n over k, also called the "choose"
+function. The result is equivalent to:
+
+ ( n ) n!
+ | - | = -------
+ ( k ) k!(n-k)!
+
+This method was added in v1.84 of Math::BigInt (April 2007).
+
=head2 blsft()
- $x->blsft($y); # left shift
+ $x->blsft($y); # left shift in base 2
$x->blsft($y,$n); # left shift, in base $n (like 10)
=head2 brsft()
- $x->brsft($y); # right shift
+ $x->brsft($y); # right shift in base 2
$x->brsft($y,$n); # right shift, in base $n (like 10)
=head2 band()
=item Creating numbers
- * When you create a number, you can give it's desired A or P via:
+ * When you create a number, you can give the desired A or P via:
$x = Math::BigInt->new($number,$A,$P);
* Only one of A or P can be defined, otherwise the result is NaN
* If no A or P is give ($x = Math::BigInt->new($number) form), then the
$x will be what was in effect when $x was created)
* If given undef for A and P, B<no> rounding will occur, and the globals will
B<not> be used. This is used by subclasses to create numbers without
- suffering rounding in the parent. Thus a subclass is able to have it's own
+ suffering rounding in the parent. Thus a subclass is able to have its own
globals enforced upon creation of a number by using
C<< $x = Math::BigInt->new($number,undef,undef) >>:
All other object methods and overloaded functions can be directly inherited
from the parent class.
-At the very minimum, any subclass will need to provide it's own C<new()> and can
+At the very minimum, any subclass will need to provide its own C<new()> and can
store additional hash keys in the object. There are also some package globals
that must be defined, e.g.:
=item blog()
+=item bexp()
+
=back
Beware: This list is not complete.
drop the leading '+'. The old code would return '+3', the new returns '3'.
This is to be consistent with Perl and to make C<cmp> (especially with
overloading) to work as you expect. It also solves problems with C<Test.pm>,
-because it's C<ok()> uses 'eq' internally.
+because its C<ok()> uses 'eq' internally.
Mark Biggar said, when asked about to drop the '+' altogether, or make only
C<cmp> work: