📄 calc.pm
字号:
{ $xv->[0] = $xv->[0] - ($xv->[1] = int($xv->[0] * $RBASE)) * $MBASE; }; return $xv; } # shortcut for result == 0 if ( ((@$xv == 1) && ($xv->[0] == 0)) || ((@$yv == 1) && ($yv->[0] == 0)) ) { @$xv = (0); return $xv; } # since multiplying $x with $x fails, make copy in this case $yv = [@$xv] if $xv == $yv; # same references? if ($LEN_CONVERT != 0) { $c->_to_small($xv); $c->_to_small($yv); } my @prod = (); my ($prod,$car,$cty,$xi,$yi); for $xi (@$xv) { $car = 0; $cty = 0; # slow variant# for $yi (@$yv)# {# $prod = $xi * $yi + ($prod[$cty] || 0) + $car;# $prod[$cty++] =# $prod - ($car = int($prod * RBASE)) * $MBASE; # see USE_MUL# }# $prod[$cty] += $car if $car; # need really to check for 0?# $xi = shift @prod; # faster variant # looping through this if $xi == 0 is silly - so optimize it away! $xi = (shift @prod || 0), next if $xi == 0; for $yi (@$yv) { $prod = $xi * $yi + ($prod[$cty] || 0) + $car;## this is actually a tad slower## $prod = $prod[$cty]; $prod += ($car + $xi * $yi); # no ||0 here $prod[$cty++] = $prod - ($car = int($prod * $RBASE)) * $MBASE; # see USE_MUL } $prod[$cty] += $car if $car; # need really to check for 0? $xi = shift @prod || 0; # || 0 makes v5.005_3 happy } push @$xv, @prod; if ($LEN_CONVERT != 0) { $c->_to_large($yv); $c->_to_large($xv); } else { __strip_zeros($xv); } $xv; } sub _mul_use_div { # (ref to int_num_array, ref to int_num_array) # multiply two numbers in internal representation # modifies first arg, second need not be different from first my ($c,$xv,$yv) = @_; # shortcut for two very short numbers (improved by Nathan Zook) # works also if xv and yv are the same reference if ((@$xv == 1) && (@$yv == 1)) { if (($xv->[0] *= $yv->[0]) >= $MBASE) { $xv->[0] = $xv->[0] - ($xv->[1] = int($xv->[0] / $MBASE)) * $MBASE; }; return $xv; } # shortcut for result == 0 if ( ((@$xv == 1) && ($xv->[0] == 0)) || ((@$yv == 1) && ($yv->[0] == 0)) ) { @$xv = (0); return $xv; } # since multiplying $x with $x fails, make copy in this case $yv = [@$xv] if $xv == $yv; # same references? if ($LEN_CONVERT != 0) { $c->_to_small($xv); $c->_to_small($yv); } my @prod = (); my ($prod,$car,$cty,$xi,$yi); for $xi (@$xv) { $car = 0; $cty = 0; # looping through this if $xi == 0 is silly - so optimize it away! $xi = (shift @prod || 0), next if $xi == 0; for $yi (@$yv) { $prod = $xi * $yi + ($prod[$cty] || 0) + $car; $prod[$cty++] = $prod - ($car = int($prod / $MBASE)) * $MBASE; } $prod[$cty] += $car if $car; # need really to check for 0? $xi = shift @prod || 0; # || 0 makes v5.005_3 happy } push @$xv, @prod; if ($LEN_CONVERT != 0) { $c->_to_large($yv); $c->_to_large($xv); } else { __strip_zeros($xv); } $xv; } sub _div_use_mul { # ref to array, ref to array, modify first array and return remainder if # in list context my ($c,$x,$yorg) = @_; if (@$x == 1 && @$yorg == 1) { # shortcut, $yorg and $x are two small numbers if (wantarray) { my $r = [ $x->[0] % $yorg->[0] ]; $x->[0] = int($x->[0] / $yorg->[0]); return ($x,$r); } else { $x->[0] = int($x->[0] / $yorg->[0]); return $x; } } if (@$yorg == 1) { my $rem; $rem = _mod($c,[ @$x ],$yorg) if wantarray; # shortcut, $y is < $BASE my $j = scalar @$x; my $r = 0; my $y = $yorg->[0]; my $b; while ($j-- > 0) { $b = $r * $MBASE + $x->[$j]; $x->[$j] = int($b/$y); $r = $b % $y; } pop @$x if @$x > 1 && $x->[-1] == 0; # splice up a leading zero return ($x,$rem) if wantarray; return $x; } my $y = [ @$yorg ]; # always make copy to preserve if ($LEN_CONVERT != 0) { $c->_to_small($x); $c->_to_small($y); } my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0); $car = $bar = $prd = 0; if (($dd = int($MBASE/($y->[-1]+1))) != 1) { for $xi (@$x) { $xi = $xi * $dd + $car; $xi -= ($car = int($xi * $RBASE)) * $MBASE; # see USE_MUL } push(@$x, $car); $car = 0; for $yi (@$y) { $yi = $yi * $dd + $car; $yi -= ($car = int($yi * $RBASE)) * $MBASE; # see USE_MUL } } else { push(@$x, 0); } @q = (); ($v2,$v1) = @$y[-2,-1]; $v2 = 0 unless $v2; while ($#$x > $#$y) { ($u2,$u1,$u0) = @$x[-3..-1]; $u2 = 0 unless $u2; #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n" # if $v1 == 0; $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$MBASE+$u1)/$v1)); --$q while ($v2*$q > ($u0*$MBASE+$u1-$q*$v1)*$MBASE+$u2); if ($q) { ($car, $bar) = (0,0); for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) { $prd = $q * $y->[$yi] + $car; $prd -= ($car = int($prd * $RBASE)) * $MBASE; # see USE_MUL $x->[$xi] += $MBASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0)); } if ($x->[-1] < $car + $bar) { $car = 0; --$q; for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) { $x->[$xi] -= $MBASE if ($car = (($x->[$xi] += $y->[$yi] + $car) > $MBASE)); } } } pop(@$x); unshift(@q, $q); } if (wantarray) { @d = (); if ($dd != 1) { $car = 0; for $xi (reverse @$x) { $prd = $car * $MBASE + $xi; $car = $prd - ($tmp = int($prd / $dd)) * $dd; # see USE_MUL unshift(@d, $tmp); } } else { @d = @$x; } @$x = @q; my $d = \@d; if ($LEN_CONVERT != 0) { $c->_to_large($x); $c->_to_large($d); } else { __strip_zeros($x); __strip_zeros($d); } return ($x,$d); } @$x = @q; if ($LEN_CONVERT != 0) { $c->_to_large($x); } else { __strip_zeros($x); } $x; }sub _div_use_div { # ref to array, ref to array, modify first array and return remainder if # in list context my ($c,$x,$yorg) = @_; if (@$x == 1 && @$yorg == 1) { # shortcut, $yorg and $x are two small numbers if (wantarray) { my $r = [ $x->[0] % $yorg->[0] ]; $x->[0] = int($x->[0] / $yorg->[0]); return ($x,$r); } else { $x->[0] = int($x->[0] / $yorg->[0]); return $x; } } if (@$yorg == 1) { my $rem; $rem = _mod($c,[ @$x ],$yorg) if wantarray; # shortcut, $y is < $BASE my $j = scalar @$x; my $r = 0; my $y = $yorg->[0]; my $b; while ($j-- > 0) { $b = $r * $MBASE + $x->[$j]; $x->[$j] = int($b/$y); $r = $b % $y; } pop @$x if @$x > 1 && $x->[-1] == 0; # splice up a leading zero return ($x,$rem) if wantarray; return $x; } my $y = [ @$yorg ]; # always make copy to preserve if ($LEN_CONVERT != 0) { $c->_to_small($x); $c->_to_small($y); } my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0); $car = $bar = $prd = 0; if (($dd = int($MBASE/($y->[-1]+1))) != 1) { for $xi (@$x) { $xi = $xi * $dd + $car; $xi -= ($car = int($xi / $MBASE)) * $MBASE; } push(@$x, $car); $car = 0; for $yi (@$y) { $yi = $yi * $dd + $car; $yi -= ($car = int($yi / $MBASE)) * $MBASE; } } else { push(@$x, 0); } @q = (); ($v2,$v1) = @$y[-2,-1]; $v2 = 0 unless $v2; while ($#$x > $#$y) { ($u2,$u1,$u0) = @$x[-3..-1]; $u2 = 0 unless $u2; #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n" # if $v1 == 0; $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$MBASE+$u1)/$v1)); --$q while ($v2*$q > ($u0*$MBASE+$u1-$q*$v1)*$MBASE+$u2); if ($q) { ($car, $bar) = (0,0); for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) { $prd = $q * $y->[$yi] + $car; $prd -= ($car = int($prd / $MBASE)) * $MBASE; $x->[$xi] += $MBASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0)); } if ($x->[-1] < $car + $bar) { $car = 0; --$q; for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) { $x->[$xi] -= $MBASE if ($car = (($x->[$xi] += $y->[$yi] + $car) > $MBASE)); } } } pop(@$x); unshift(@q, $q); } if (wantarray) { @d = (); if ($dd != 1) { $car = 0; for $xi (reverse @$x) { $prd = $car * $MBASE + $xi; $car = $prd - ($tmp = int($prd / $dd)) * $dd; unshift(@d, $tmp); } } else { @d = @$x; } @$x = @q; my $d = \@d; if ($LEN_CONVERT != 0) { $c->_to_large($x); $c->_to_large($d); } else { __strip_zeros($x); __strip_zeros($d); } return ($x,$d); } @$x = @q; if ($LEN_CONVERT != 0) { $c->_to_large($x); } else { __strip_zeros($x); } $x; }############################################################################### testingsub _acmp { # internal absolute post-normalized compare (ignore signs) # ref to array, ref to array, return <0, 0, >0 # arrays must have at least one entry; this is not checked for my ($c,$cx,$cy) = @_; # fast comp based on number of array elements (aka pseudo-length) my $lxy = scalar @$cx - scalar @$cy; return -1 if $lxy < 0; # already differs, ret return 1 if $lxy > 0; # ditto # now calculate length based on digits, not parts # we need only the length of the last element, since both array have the # same number of parts $lxy = length(int($cx->[-1])) - length(int($cy->[-1])); return -1 if $lxy < 0; return 1 if $lxy > 0; # hm, same lengths, but same contents? So we need to check all parts: my $a; my $j = scalar @$cx - 1; # manual way (abort if unequal, good for early ne) while ($j >= 0) { last if ($a = $cx->[$j] - $cy->[$j]); $j--; } return 1 if $a > 0; return -1 if $a < 0; 0; # numbers are equal }sub _len {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -