⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 calc.pm

📁 source of perl for linux application,
💻 PM
📖 第 1 页 / 共 5 页
字号:
          {          $xv->[0] =              $xv->[0] - ($xv->[1] = $xv->[0] / $BASE) * $BASE;          };      return $xv;      }    # $x * 0 => 0    if ($yv->[0] == 0)      {      @$xv = (0);      return $xv;      }    # multiply a large number a by a single element one, so speed up    my $y = $yv->[0]; my $car = 0;    foreach my $i (@$xv)      {      #$i = $i * $y + $car; $car = $i / $BASE; $i -= $car * $BASE;      $i = $i * $y + $car; $i -= ($car = $i / $BASE) * $BASE;      }    push @$xv, $car if $car != 0;    return $xv;    }  # shortcut for result $x == 0 => result = 0  return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) );   # since multiplying $x with $x fails, make copy in this case  $yv = [@$xv] if $xv == $yv;	# same references?  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 = $prod / $BASE) * $BASE;      }    $prod[$cty] += $car if $car; # need really to check for 0?    $xi = shift @prod || 0;	# || 0 makes v5.005_3 happy    }  push @$xv, @prod;  $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) = @_;  if (@$yv == 1)    {    # shortcut for two small numbers, also handles $x == 0    if (@$xv == 1)      {      # shortcut for two very short numbers (improved by Nathan Zook)      # works also if xv and yv are the same reference, and handles also $x == 0      if (($xv->[0] *= $yv->[0]) >= $BASE)          {          $xv->[0] =              $xv->[0] - ($xv->[1] = int($xv->[0] / $BASE)) * $BASE;          };      return $xv;      }    # $x * 0 => 0    if ($yv->[0] == 0)      {      @$xv = (0);      return $xv;      }    # multiply a large number a by a single element one, so speed up    my $y = $yv->[0]; my $car = 0;    foreach my $i (@$xv)      {      $i = $i * $y + $car; $car = int($i / $BASE); $i -= $car * $BASE;      # This (together with use integer;) does not work on 32-bit Perls      #$i = $i * $y + $car; $i -= ($car = $i / $BASE) * $BASE;      }    push @$xv, $car if $car != 0;    return $xv;    }  # shortcut for result $x == 0 => result = 0  return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) );   # since multiplying $x with $x fails, make copy in this case  $yv = [@$xv] if $xv == $yv;	# same references?  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 / $BASE)) * $BASE;      }    $prod[$cty] += $car if $car; # need really to check for 0?    $xi = shift @prod || 0;	# || 0 makes v5.005_3 happy    }  push @$xv, @prod;  # can't have leading zeros#  __strip_zeros($xv);  $xv;  }                                                                             sub _div_use_mul  {  # ref to array, ref to array, modify first array and return remainder if   # in list context  # see comments in _div_use_div() for more explanations  my ($c,$x,$yorg) = @_;    # the general div algorithmn here is about O(N*N) and thus quite slow, so  # we first check for some special cases and use shortcuts to handle them.  # This works, because we store the numbers in a chunked format where each  # element contains 5..7 digits (depending on system).  # if both numbers have only one element:  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 x has more than one, but y has only one element:  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 * $BASE + $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;    }  # now x and y have more than one element  # check whether y has more elements than x, if yet, the result will be 0  if (@$yorg > @$x)    {    my $rem;    $rem = [@$x] if wantarray;                  # make copy    splice (@$x,1);                             # keep ref to original array    $x->[0] = 0;                                # set to 0    return ($x,$rem) if wantarray;              # including remainder?    return $x;					# only x, which is [0] now    }  # check whether the numbers have the same number of elements, in that case  # the result will fit into one element and can be computed efficiently  if (@$yorg == @$x)    {    my $rem;    # if $yorg has more digits than $x (it's leading element is longer than    # the one from $x), the result will also be 0:    if (length(int($yorg->[-1])) > length(int($x->[-1])))      {      $rem = [@$x] if wantarray;		# make copy      splice (@$x,1);				# keep ref to org array      $x->[0] = 0;				# set to 0      return ($x,$rem) if wantarray;		# including remainder?      return $x;      }    # now calculate $x / $yorg    if (length(int($yorg->[-1])) == length(int($x->[-1])))      {      # same length, so make full compare      my $a = 0; my $j = scalar @$x - 1;      # manual way (abort if unequal, good for early ne)      while ($j >= 0)        {        last if ($a = $x->[$j] - $yorg->[$j]); $j--;        }      # $a contains the result of the compare between X and Y      # a < 0: x < y, a == 0: x == y, a > 0: x > y      if ($a <= 0)        {        $rem = [ 0 ];                   # a = 0 => x == y => rem 0        $rem = [@$x] if $a != 0;        # a < 0 => x < y => rem = x        splice(@$x,1);                  # keep single element        $x->[0] = 0;                    # if $a < 0        $x->[0] = 1 if $a == 0;         # $x == $y        return ($x,$rem) if wantarray;        return $x;        }      # $x >= $y, so proceed normally      }    }  # all other cases:  my $y = [ @$yorg ];				# always make copy to preserve  my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);  $car = $bar = $prd = 0;  if (($dd = int($BASE/($y->[-1]+1))) != 1)     {    for $xi (@$x)       {      $xi = $xi * $dd + $car;      $xi -= ($car = int($xi * $RBASE)) * $BASE;	# see USE_MUL      }    push(@$x, $car); $car = 0;    for $yi (@$y)       {      $yi = $yi * $dd + $car;      $yi -= ($car = int($yi * $RBASE)) * $BASE;	# 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*$BASE+$u1)/$v1));    --$q while ($v2*$q > ($u0*$BASE+$u1-$q*$v1)*$BASE+$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)) * $BASE;	# see USE_MUL	$x->[$xi] += $BASE 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] -= $BASE	   if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE));	  }	}         }    pop(@$x);    unshift(@q, $q);    }  if (wantarray)     {    @d = ();    if ($dd != 1)        {      $car = 0;       for $xi (reverse @$x)         {        $prd = $car * $BASE + $xi;        $car = $prd - ($tmp = int($prd / $dd)) * $dd; # see USE_MUL        unshift(@d, $tmp);        }      }    else       {      @d = @$x;      }    @$x = @q;    my $d = \@d;     __strip_zeros($x);    __strip_zeros($d);    return ($x,$d);    }  @$x = @q;  __strip_zeros($x);  $x;  }sub _div_use_div_64  {  # ref to array, ref to array, modify first array and return remainder if   # in list context  # This version works on 64 bit integers  my ($c,$x,$yorg) = @_;  use integer;  # the general div algorithmn here is about O(N*N) and thus quite slow, so  # we first check for some special cases and use shortcuts to handle them.  # This works, because we store the numbers in a chunked format where each  # element contains 5..7 digits (depending on system).  # if both numbers have only one element:  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 x has more than one, but y has only one element:  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 * $BASE + $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;    }  # now x and y have more than one element  # check whether y has more elements than x, if yet, the result will be 0  if (@$yorg > @$x)    {    my $rem;    $rem = [@$x] if wantarray;			# make copy    splice (@$x,1);				# keep ref to original array    $x->[0] = 0;				# set to 0    return ($x,$rem) if wantarray;		# including remainder?    return $x;					# only x, which is [0] now    }  # check whether the numbers have the same number of elements, in that case  # the result will fit into one element and can be computed efficiently  if (@$yorg == @$x)    {    my $rem;    # if $yorg has more digits than $x (it's leading element is longer than    # the one from $x), the result will also be 0:    if (length(int($yorg->[-1])) > length(int($x->[-1])))      {      $rem = [@$x] if wantarray;		# make copy      splice (@$x,1);				# keep ref to org array      $x->[0] = 0;				# set to 0      return ($x,$rem) if wantarray;		# including remainder?      return $x;      }    # now calculate $x / $yorg    if (length(int($yorg->[-1])) == length(int($x->[-1])))      {      # same length, so make full compare      my $a = 0; my $j = scalar @$x - 1;      # manual way (abort if unequal, good for early ne)      while ($j >= 0)        {        last if ($a = $x->[$j] - $yorg->[$j]); $j--;        }      # $a contains the result of the compare between X and Y      # a < 0: x < y, a == 0: x == y, a > 0: x > y      if ($a <= 0)        {        $rem = [ 0 ];			# a = 0 => x == y => rem 0        $rem = [@$x] if $a != 0;	# a < 0 => x < y => rem = x        splice(@$x,1);			# keep single element        $x->[0] = 0;			# if $a < 0        $x->[0] = 1 if $a == 0; 	# $x == $y        return ($x,$rem) if wantarray;	# including remainder?        return $x;        }      # $x >= $y, so proceed normally      }    }  # all other cases:  my $y = [ @$yorg ];				# always make copy to preserve   my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);  $car = $bar = $prd = 0;  if (($dd = int($BASE/($y->[-1]+1))) != 1)     {    for $xi (@$x)       {      $xi = $xi * $dd + $car;      $xi -= ($car = int($xi / $BASE)) * $BASE;      }    push(@$x, $car); $car = 0;    for $yi (@$y)       {      $yi = $yi * $dd + $car;      $yi -= ($car = int($yi / $BASE)) * $BASE;      }    }  else     {    push(@$x, 0);    }  # @q will accumulate the final result, $q contains the current computed  # part of the final result  @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*$BASE+$u1)/$v1));    --$q while ($v2*$q > ($u0*$BASE+$u1-$q*$v1)*$BASE+$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 / $BASE)) * $BASE;	$x->[$xi] += $BASE 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] -= $BASE	   if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE));	  }	}         }    pop(@$x); unshift(@q, $q);    }  if (wantarray)     {    @d = ();    if ($dd != 1)        {      $car = 0;       for $xi (reverse @$x)         {        $prd = $car * $BASE + $xi;        $car = $prd - ($tmp = int($prd / $dd)) * $dd;        unshift(@d, $tmp);        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -