📄 bigint.pm
字号:
{ ($self,$x,$y) = objectify(2,@_); } return $upgrade->bacmp($x,$y) if defined $upgrade && ((!$x->isa($self)) || (!$y->isa($self))); if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/)) { # handle +-inf and NaN return undef if (($x->{sign} eq $nan) || ($y->{sign} eq $nan)); return 0 if $x->{sign} =~ /^[+-]inf$/ && $y->{sign} =~ /^[+-]inf$/; return +1; # inf is always bigger } $CALC->_acmp($x->{value},$y->{value}); # lib does only 0,1,-1 }sub badd { # add second arg (BINT or string) to first (BINT) (modifies first) # return result as BINT # 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('badd'); return $upgrade->badd($x,$y,@r) if defined $upgrade && ((!$x->isa($self)) || (!$y->isa($self))); $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} = $CALC->_add($x->{value},$y->{value}); # same sign, abs add $x->{sign} = $sx; } else { my $a = $CALC->_acmp ($y->{value},$x->{value}); # absolute compare if ($a > 0) { #print "swapped sub (a=$a)\n"; $x->{value} = $CALC->_sub($y->{value},$x->{value},1); # abs sub w/ swap $x->{sign} = $sy; } elsif ($a == 0) { # speedup, if equal, set result to 0 #print "equal sub, result = 0\n"; $x->{value} = $CALC->_zero(); $x->{sign} = '+'; } else # a < 0 { #print "unswapped sub (a=$a)\n"; $x->{value} = $CALC->_sub($x->{value}, $y->{value}); # abs sub $x->{sign} = $sx; } } $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0; $x; }sub bsub { # (BINT or num_str, BINT or num_str) return num_str # subtract second arg from first, modify first # 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('bsub');# upgrade done by badd():# return $upgrade->badd($x,$y,@r) if defined $upgrade &&# ((!$x->isa($self)) || (!$y->isa($self))); if ($y->is_zero()) { $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0; return $x; } $y->{sign} =~ tr/+\-/-+/; # does nothing for NaN $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 round necc. }sub binc { # increment arg by one my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); return $x if $x->modify('binc'); if ($x->{sign} eq '+') { $x->{value} = $CALC->_inc($x->{value}); $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0; return $x; } elsif ($x->{sign} eq '-') { $x->{value} = $CALC->_dec($x->{value}); $x->{sign} = '+' if $CALC->_is_zero($x->{value}); # -1 +1 => -0 => +0 $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0; return $x; } # inf, nan handling etc $x->badd($self->__one(),$a,$p,$r); # badd does round }sub bdec { # decrement arg by one my ($self,$x,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); return $x if $x->modify('bdec'); my $zero = $CALC->_is_zero($x->{value}) && $x->{sign} eq '+'; # <= 0 if (($x->{sign} eq '-') || $zero) { $x->{value} = $CALC->_inc($x->{value}); $x->{sign} = '-' if $zero; # 0 => 1 => -1 $x->{sign} = '+' if $CALC->_is_zero($x->{value}); # -1 +1 => -0 => +0 $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0; return $x; } # > 0 elsif ($x->{sign} eq '+') { $x->{value} = $CALC->_dec($x->{value}); $x->round($a,$p,$r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0; return $x; } # inf, nan handling etc $x->badd($self->__one('-'),$a,$p,$r); # badd does round } sub blog { # not implemented yet my ($self,$x,$base,$a,$p,$r) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); return $upgrade->blog($x,$base,$a,$p,$r) if defined $upgrade; return $x->bnan(); } sub blcm { # (BINT or num_str, BINT or num_str) return BINT # does not modify arguments, but returns new object # Lowest Common Multiplicator my $y = shift; my ($x); if (ref($y)) { $x = $y->copy(); } else { $x = $class->new($y); } while (@_) { $x = __lcm($x,shift); } $x; }sub bgcd { # (BINT or num_str, BINT or num_str) return BINT # does not modify arguments, but returns new object # GCD -- Euclids algorithm, variant C (Knuth Vol 3, pg 341 ff) my $y = shift; $y = __PACKAGE__->new($y) if !ref($y); my $self = ref($y); my $x = $y->copy(); # keep arguments if ($CALC->can('_gcd')) { while (@_) { $y = shift; $y = $self->new($y) if !ref($y); next if $y->is_zero(); return $x->bnan() if $y->{sign} !~ /^[+-]$/; # y NaN? $x->{value} = $CALC->_gcd($x->{value},$y->{value}); last if $x->is_one(); } } else { while (@_) { $y = shift; $y = $self->new($y) if !ref($y); $x = __gcd($x,$y->copy()); last if $x->is_one(); # _gcd handles NaN } } $x->babs(); }sub bnot { # (num_str or BINT) return BINT # represent ~x as twos-complement number # we don't need $self, so undef instead of ref($_[0]) make it slightly faster my ($self,$x,$a,$p,$r) = ref($_[0]) ? (undef,@_) : objectify(1,@_); return $x if $x->modify('bnot'); $x->bneg()->bdec(); # bdec already does round }# is_foo test routinessub is_zero { # return true if arg (BINT or num_str) is zero (array '+', '0') # we don't need $self, so undef instead of ref($_[0]) make it slightly faster my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); return 0 if $x->{sign} !~ /^\+$/; # -, NaN & +-inf aren't $CALC->_is_zero($x->{value}); }sub is_nan { # return true if arg (BINT or num_str) is NaN my ($self,$x) = ref($_[0]) ? (ref($_[0]),$_[0]) : objectify(1,@_); return 1 if $x->{sign} eq $nan; 0; }sub is_inf { # return true if arg (BINT or num_str) is +-inf my ($self,$x,$sign) = ref($_[0]) ? (ref($_[0]),@_) : objectify(1,@_); $sign = '' if !defined $sign; return 1 if $sign eq $x->{sign}; # match ("+inf" eq "+inf") return 0 if $sign !~ /^([+-]|)$/; if ($sign eq '') { return 1 if ($x->{sign} =~ /^[+-]inf$/); return 0; } $sign = quotemeta($sign.'inf'); return 1 if ($x->{sign} =~ /^$sign$/); 0; }sub is_one { # return true if arg (BINT or num_str) is +1 # or -1 if sign is given # we don't need $self, so undef instead of ref($_[0]) make it slightly faster my ($self,$x,$sign) = ref($_[0]) ? (undef,@_) : objectify(1,@_); $sign = '' if !defined $sign; $sign = '+' if $sign ne '-'; return 0 if $x->{sign} ne $sign; # -1 != +1, NaN, +-inf aren't either $CALC->_is_one($x->{value}); }sub is_odd { # return true when arg (BINT or num_str) is odd, false for even # we don't need $self, so undef instead of ref($_[0]) make it slightly faster my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't $CALC->_is_odd($x->{value}); }sub is_even { # return true when arg (BINT or num_str) is even, false for odd # we don't need $self, so undef instead of ref($_[0]) make it slightly faster my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); return 0 if $x->{sign} !~ /^[+-]$/; # NaN & +-inf aren't $CALC->_is_even($x->{value}); }sub is_positive { # return true when arg (BINT or num_str) is positive (>= 0) # we don't need $self, so undef instead of ref($_[0]) make it slightly faster my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); return 1 if $x->{sign} =~ /^\+/; 0; }sub is_negative { # return true when arg (BINT or num_str) is negative (< 0) # we don't need $self, so undef instead of ref($_[0]) make it slightly faster my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); return 1 if ($x->{sign} =~ /^-/); 0; }sub is_int { # return true when arg (BINT or num_str) is an integer # always true for BigInt, but different for Floats # we don't need $self, so undef instead of ref($_[0]) make it slightly faster my ($self,$x) = ref($_[0]) ? (undef,$_[0]) : objectify(1,@_); $x->{sign} =~ /^[+-]$/ ? 1 : 0; # inf/-inf/NaN aren't }###############################################################################sub bmul { # multiply two numbers -- stolen from Knuth Vol 2 pg 233 # (BINT or num_str, BINT or num_str) return BINT # 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('bmul'); return $x->bnan() if (($x->{sign} eq $nan) || ($y->{sign} eq $nan)); # inf handling if (($x->{sign} =~ /^[+-]inf$/) || ($y->{sign} =~ /^[+-]inf$/)) { return $x->bnan() if $x->is_zero() || $y->is_zero(); # result will always be +-inf: # +inf * +/+inf => +inf, -inf * -/-inf => +inf # +inf * -/-inf => -inf, -inf * +/+inf => -inf return $x->binf() if ($x->{sign} =~ /^\+/ && $y->{sign} =~ /^\+/); return $x->binf() if ($x->{sign} =~ /^-/ && $y->{sign} =~ /^-/); return $x->binf('-'); } return $upgrade->bmul($x,$y,@r) if defined $upgrade && $y->isa($upgrade); $r[3] = $y; # no push here $x->{sign} = $x->{sign} eq $y->{sign} ? '+' : '-'; # +1 * +1 or -1 * -1 => + $x->{value} = $CALC->_mul($x->{value},$y->{value}); # do actual math $x->{sign} = '+' if $CALC->_is_zero($x->{value}); # no -0 $x->round(@r) if !exists $x->{_f} || $x->{_f} & MB_NEVER_ROUND == 0; $x; }sub _div_inf { # helper function that handles +-inf cases for bdiv()/bmod() to reuse code my ($self,$x,$y) = @_; # NaN if x == NaN or y == NaN or x==y==0 return wantarray ? ($x->bnan(),$self->bnan()) : $x->bnan() if (($x->is_nan() || $y->is_nan()) || ($x->is_zero() && $y->is_zero())); # +-inf / +-inf == NaN, reminder also NaN if (($x->{sign} =~ /^[+-]inf$/) && ($y->{sign} =~ /^[+-]inf$/)) { return wantarray ? ($x->bnan(),$self->bnan()) : $x->bnan(); } # x / +-inf => 0, remainder x (works even if x == 0) if ($y->{sign} =~ /^[+-]inf$/) { my $t = $x->copy(); # bzero clobbers up $x return wantarray ? ($x->bzero(),$t) : $x->bzero() } # 5 / 0 => +inf, -6 / 0 => -inf # +inf / 0 = inf, inf, and -inf / 0 => -inf, -inf # exception: -8 / 0 has remainder -8, not 8 # exception: -inf / 0 has remainder -inf, not inf if ($y->is_zero()) { # +-inf / 0 => special case for -inf return wantarray ? ($x,$x->copy()) : $x if $x->is_inf(); if (!$x->is_zero() && !$x->is_inf()) { my $t = $x->copy(); # binf clobbers up $x return wantarray ? ($x->binf($x->{sign}),$t) : $x->binf($x->{sign}) } } # last case: +-inf / ordinary number my $sign = '+inf'; $sign = '-inf' if substr($x->{sign},0,1) ne $y->{sign}; $x->{sign} = $sign; return wantarray ? ($x,$self->bzero()) : $x; }sub bdiv { # (dividend: BINT or num_str, divisor: BINT or num_str) return # (BINT,BINT) (quo,rem) or BINT (only rem) # 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('bdiv'); return $self->_div_inf($x,$y) if (($x->{sign} !~ /^[+-]$/) || ($y->{sign} !~ /^[+-]$/) || $y->is_zero()); return $upgrade->bdiv($upgrade->new($x),$y,@r) if defined $upgrade && !$y->isa($self); $r[3] = $y; # no push! # 0 / something
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -