CryptX
view release on metacpan or search on metacpan
lib/Math/BigInt/LTM.pm view on Meta::CPAN
return $n;
}
### same as _sadd() in Math::BigInt::Lib
# Signed addition. If the flag is false, $xa might be modified, but not $ya. If
# the false is true, $ya might be modified, but not $xa.
sub _sadd {
my $class = shift;
my ($xa, $xs, $ya, $ys, $flag) = @_;
my ($za, $zs);
# If the signs are equal we can add them (-5 + -3 => -(5 + 3) => -8)
if ($xs eq $ys) {
if ($flag) {
$za = $class -> _add($ya, $xa);
} else {
$za = $class -> _add($xa, $ya);
}
$zs = $class -> _is_zero($za) ? '+' : $xs;
return $za, $zs;
}
my $acmp = $class -> _acmp($xa, $ya); # abs(x) = abs(y)
if ($acmp == 0) { # x = -y or -x = y
$za = $class -> _zero();
$zs = '+';
return $za, $zs;
}
if ($acmp > 0) { # abs(x) > abs(y)
$za = $class -> _sub($xa, $ya, $flag);
$zs = $xs;
} else { # abs(x) < abs(y)
$za = $class -> _sub($ya, $xa, !$flag);
$zs = $ys;
}
return $za, $zs;
}
### same as _ssub() in Math::BigInt::Lib
# Signed subtraction. If the flag is false, $xa might be modified, but not $ya.
# If the false is true, $ya might be modified, but not $xa.
sub _ssub {
my $class = shift;
my ($xa, $xs, $ya, $ys, $flag) = @_;
# Swap sign of second operand and let _sadd() do the job.
$ys = $ys eq '+' ? '-' : '+';
$class -> _sadd($xa, $xs, $ya, $ys, $flag);
}
### same as _log_int() in Math::BigInt::Lib
sub _log_int {
# calculate integer log of $x to base $base
# ref to array, ref to array - return ref to array
my ($class, $x, $base) = @_;
# X == 0 => NaN
return if $class -> _is_zero($x);
$base = $class -> _new(2) unless defined($base);
$base = $class -> _new($base) unless ref($base);
# BASE 0 or 1 => NaN
return if $class -> _is_zero($base) || $class -> _is_one($base);
# X == 1 => 0 (is exact)
if ($class -> _is_one($x)) {
return $class -> _zero(), 1;
}
my $cmp = $class -> _acmp($x, $base);
# X == BASE => 1 (is exact)
if ($cmp == 0) {
return $class -> _one(), 1;
}
# 1 < X < BASE => 0 (is truncated)
if ($cmp < 0) {
return $class -> _zero(), 0;
}
my $y;
# log(x) / log(b) = log(xm * 10^xe) / log(bm * 10^be)
# = (log(xm) + xe*(log(10))) / (log(bm) + be*log(10))
{
my $x_str = $class -> _str($x);
my $b_str = $class -> _str($base);
my $xm = "." . $x_str;
my $bm = "." . $b_str;
my $xe = length($x_str);
my $be = length($b_str);
my $log10 = log(10);
my $guess = int((log($xm) + $xe * $log10) / (log($bm) + $be * $log10));
$y = $class -> _new($guess);
}
my $trial = $class -> _pow($class -> _copy($base), $y);
my $acmp = $class -> _acmp($trial, $x);
# Did we get the exact result?
return $y, 1 if $acmp == 0;
# Too small?
while ($acmp < 0) {
$trial = $class -> _mul($trial, $base);
$y = $class -> _inc($y);
$acmp = $class -> _acmp($trial, $x);
}
# Too big?
while ($acmp > 0) {
$trial = $class -> _div($trial, $base);
$y = $class -> _dec($y);
$acmp = $class -> _acmp($trial, $x);
}
return $y, 1 if $acmp == 0; # result is exact
( run in 0.731 second using v1.01-cache-2.11-cpan-39bf76dae61 )