home *** CD-ROM | disk | FTP | other *** search
/ Netrunner 2004 October / NETRUNNER0410.ISO / regular / ActivePerl-5.8.4.810-MSWin32-x86.msi / _06416b78c93504631080394b43a94d0e < prev    next >
Text File  |  2004-06-01  |  63KB  |  2,136 lines

  1. package Math::BigInt::Calc;
  2.  
  3. use 5.005;
  4. use strict;
  5. # use warnings;    # dont use warnings for older Perls
  6.  
  7. use vars qw/$VERSION/;
  8.  
  9. $VERSION = '0.40';
  10.  
  11. # Package to store unsigned big integers in decimal and do math with them
  12.  
  13. # Internally the numbers are stored in an array with at least 1 element, no
  14. # leading zero parts (except the first) and in base 1eX where X is determined
  15. # automatically at loading time to be the maximum possible value
  16.  
  17. # todo:
  18. # - fully remove funky $# stuff (maybe)
  19.  
  20. # USE_MUL: due to problems on certain os (os390, posix-bc) "* 1e-5" is used
  21. # instead of "/ 1e5" at some places, (marked with USE_MUL). Other platforms
  22. # BS2000, some Crays need USE_DIV instead.
  23. # The BEGIN block is used to determine which of the two variants gives the
  24. # correct result.
  25.  
  26. # Beware of things like:
  27. # $i = $i * $y + $car; $car = int($i / $MBASE); $i = $i % $MBASE;
  28. # This works on x86, but fails on ARM (SA1100, iPAQ) due to whoknows what
  29. # reasons. So, use this instead (slower, but correct):
  30. # $i = $i * $y + $car; $car = int($i / $MBASE); $i -= $MBASE * $car;
  31.  
  32. ##############################################################################
  33. # global constants, flags and accessory
  34.  
  35. # announce that we are compatible with MBI v1.70 and up
  36. sub api_version () { 1; }
  37.  
  38. # constants for easier life
  39. my $nan = 'NaN';
  40. my ($MBASE,$BASE,$RBASE,$BASE_LEN,$MAX_VAL,$BASE_LEN2,$BASE_LEN_SMALL);
  41. my ($AND_BITS,$XOR_BITS,$OR_BITS);
  42. my ($AND_MASK,$XOR_MASK,$OR_MASK);
  43.  
  44. sub _base_len 
  45.   {
  46.   # set/get the BASE_LEN and assorted other, connected values
  47.   # used only be the testsuite, set is used only by the BEGIN block below
  48.   shift;
  49.  
  50.   my $b = shift;
  51.   if (defined $b)
  52.     {
  53.     # find whether we can use mul or div or none in mul()/div()
  54.     # (in last case reduce BASE_LEN_SMALL)
  55.     $BASE_LEN_SMALL = $b+1;
  56.     my $caught = 0;
  57.     while (--$BASE_LEN_SMALL > 5)
  58.       {
  59.       $MBASE = int("1e".$BASE_LEN_SMALL);
  60.       $RBASE = abs('1e-'.$BASE_LEN_SMALL);        # see USE_MUL
  61.       $caught = 0;
  62.       $caught += 1 if (int($MBASE * $RBASE) != 1);    # should be 1
  63.       $caught += 2 if (int($MBASE / $MBASE) != 1);    # should be 1
  64.       last if $caught != 3;
  65.       }
  66.     # BASE_LEN is used for anything else than mul()/div()
  67.     $BASE_LEN = $BASE_LEN_SMALL;
  68.     $BASE_LEN = shift if (defined $_[0]);        # one more arg?
  69.     $BASE = int("1e".$BASE_LEN);
  70.  
  71.     $BASE_LEN2 = int($BASE_LEN_SMALL / 2);        # for mul shortcut
  72.     $MBASE = int("1e".$BASE_LEN_SMALL);
  73.     $RBASE = abs('1e-'.$BASE_LEN_SMALL);        # see USE_MUL
  74.     $MAX_VAL = $MBASE-1;
  75.     
  76.     undef &_mul;
  77.     undef &_div;
  78.  
  79.     # $caught & 1 != 0 => cannot use MUL
  80.     # $caught & 2 != 0 => cannot use DIV
  81.     # The parens around ($caught & 1) were important, indeed, if we would use
  82.     # & here.
  83.     if ($caught == 2)                # 2
  84.       {
  85.       # must USE_MUL since we cannot use DIV
  86.       *{_mul} = \&_mul_use_mul;
  87.       *{_div} = \&_div_use_mul;
  88.       }
  89.     else                    # 0 or 1
  90.       {
  91.       # can USE_DIV instead
  92.       *{_mul} = \&_mul_use_div;
  93.       *{_div} = \&_div_use_div;
  94.       }
  95.     }
  96.   return $BASE_LEN unless wantarray;
  97.   return ($BASE_LEN, $AND_BITS, $XOR_BITS, $OR_BITS, $BASE_LEN_SMALL, $MAX_VAL);
  98.   }
  99.  
  100. BEGIN
  101.   {
  102.   # from Daniel Pfeiffer: determine largest group of digits that is precisely
  103.   # multipliable with itself plus carry
  104.   # Test now changed to expect the proper pattern, not a result off by 1 or 2
  105.   my ($e, $num) = 3;    # lowest value we will use is 3+1-1 = 3
  106.   do 
  107.     {
  108.     $num = ('9' x ++$e) + 0;
  109.     $num *= $num + 1.0;
  110.     } while ("$num" =~ /9{$e}0{$e}/);    # must be a certain pattern
  111.   $e--;                 # last test failed, so retract one step
  112.   # the limits below brush the problems with the test above under the rug:
  113.   # the test should be able to find the proper $e automatically
  114.   $e = 5 if $^O =~ /^uts/;    # UTS get's some special treatment
  115.   $e = 5 if $^O =~ /^unicos/;    # unicos is also problematic (6 seems to work
  116.                 # there, but we play safe)
  117.   $e = 5 if $] < 5.006;        # cap, for older Perls
  118.   $e = 7 if $e > 7;        # cap, for VMS, OS/390 and other 64 bit systems
  119.                 # 8 fails inside random testsuite, so take 7
  120.  
  121.   # determine how many digits fit into an integer and can be safely added 
  122.   # together plus carry w/o causing an overflow
  123.  
  124.   use integer;
  125.  
  126.   ############################################################################
  127.   # the next block is no longer important
  128.  
  129.   ## this below detects 15 on a 64 bit system, because after that it becomes
  130.   ## 1e16  and not 1000000 :/ I can make it detect 18, but then I get a lot of
  131.   ## test failures. Ugh! (Tomake detect 18: uncomment lines marked with *)
  132.  
  133.   #my $bi = 5;            # approx. 16 bit
  134.   #$num = int('9' x $bi);
  135.   ## $num = 99999; # *
  136.   ## while ( ($num+$num+1) eq '1' . '9' x $bi)    # *
  137.   #while ( int($num+$num+1) eq '1' . '9' x $bi)
  138.   #  {
  139.   #  $bi++; $num = int('9' x $bi);
  140.   #  # $bi++; $num *= 10; $num += 9;    # *
  141.   #  }
  142.   #$bi--;                # back off one step
  143.   # by setting them equal, we ignore the findings and use the default
  144.   # one-size-fits-all approach from former versions
  145.   my $bi = $e;                # XXX, this should work always
  146.  
  147.   __PACKAGE__->_base_len($e,$bi);    # set and store
  148.  
  149.   # find out how many bits _and, _or and _xor can take (old default = 16)
  150.   # I don't think anybody has yet 128 bit scalars, so let's play safe.
  151.   local $^W = 0;    # don't warn about 'nonportable number'
  152.   $AND_BITS = 15; $XOR_BITS = 15; $OR_BITS = 15;
  153.  
  154.   # find max bits, we will not go higher than numberofbits that fit into $BASE
  155.   # to make _and etc simpler (and faster for smaller, slower for large numbers)
  156.   my $max = 16;
  157.   while (2 ** $max < $BASE) { $max++; }
  158.   {
  159.     no integer;
  160.     $max = 16 if $] < 5.006;    # older Perls might not take >16 too well
  161.   }
  162.   my ($x,$y,$z);
  163.   do {
  164.     $AND_BITS++;
  165.     $x = oct('0b' . '1' x $AND_BITS); $y = $x & $x;
  166.     $z = (2 ** $AND_BITS) - 1;
  167.     } while ($AND_BITS < $max && $x == $z && $y == $x);
  168.   $AND_BITS --;                        # retreat one step
  169.   do {
  170.     $XOR_BITS++;
  171.     $x = oct('0b' . '1' x $XOR_BITS); $y = $x ^ 0;
  172.     $z = (2 ** $XOR_BITS) - 1;
  173.     } while ($XOR_BITS < $max && $x == $z && $y == $x);
  174.   $XOR_BITS --;                        # retreat one step
  175.   do {
  176.     $OR_BITS++;
  177.     $x = oct('0b' . '1' x $OR_BITS); $y = $x | $x;
  178.     $z = (2 ** $OR_BITS) - 1;
  179.     } while ($OR_BITS < $max && $x == $z && $y == $x);
  180.   $OR_BITS --;                        # retreat one step
  181.   
  182.   }
  183.  
  184. ###############################################################################
  185.  
  186. sub _new
  187.   {
  188.   # (ref to string) return ref to num_array
  189.   # Convert a number from string format (without sign) to internal base
  190.   # 1ex format. Assumes normalized value as input.
  191.   my $il = length($_[1])-1;
  192.  
  193.   # < BASE_LEN due len-1 above
  194.   return [ int($_[1]) ] if $il < $BASE_LEN;    # shortcut for short numbers
  195.  
  196.   # this leaves '00000' instead of int 0 and will be corrected after any op
  197.   [ reverse(unpack("a" . ($il % $BASE_LEN+1) 
  198.     . ("a$BASE_LEN" x ($il / $BASE_LEN)), $_[1])) ];
  199.   }                                                                             
  200.   
  201. BEGIN
  202.   {
  203.   $AND_MASK = __PACKAGE__->_new( ( 2 ** $AND_BITS ));
  204.   $XOR_MASK = __PACKAGE__->_new( ( 2 ** $XOR_BITS ));
  205.   $OR_MASK = __PACKAGE__->_new( ( 2 ** $OR_BITS ));
  206.   }
  207.  
  208. sub _zero
  209.   {
  210.   # create a zero
  211.   [ 0 ];
  212.   }
  213.  
  214. sub _one
  215.   {
  216.   # create a one
  217.   [ 1 ];
  218.   }
  219.  
  220. sub _two
  221.   {
  222.   # create a two (used internally for shifting)
  223.   [ 2 ];
  224.   }
  225.  
  226. sub _ten
  227.   {
  228.   # create a 10 (used internally for shifting)
  229.   [ 10 ];
  230.   }
  231.  
  232. sub _copy
  233.   {
  234.   # make a true copy
  235.   [ @{$_[1]} ];
  236.   }
  237.  
  238. # catch and throw away
  239. sub import { }
  240.  
  241. ##############################################################################
  242. # convert back to string and number
  243.  
  244. sub _str
  245.   {
  246.   # (ref to BINT) return num_str
  247.   # Convert number from internal base 100000 format to string format.
  248.   # internal format is always normalized (no leading zeros, "-0" => "+0")
  249.   my $ar = $_[1];
  250.   my $ret = "";
  251.  
  252.   my $l = scalar @$ar;        # number of parts
  253.   return $nan if $l < 1;    # should not happen
  254.  
  255.   # handle first one different to strip leading zeros from it (there are no
  256.   # leading zero parts in internal representation)
  257.   $l --; $ret .= int($ar->[$l]); $l--;
  258.   # Interestingly, the pre-padd method uses more time
  259.   # the old grep variant takes longer (14 vs. 10 sec)
  260.   my $z = '0' x ($BASE_LEN-1);                            
  261.   while ($l >= 0)
  262.     {
  263.     $ret .= substr($z.$ar->[$l],-$BASE_LEN); # fastest way I could think of
  264.     $l--;
  265.     }
  266.   $ret;
  267.   }                                                                             
  268.  
  269. sub _num
  270.   {
  271.   # Make a number (scalar int/float) from a BigInt object 
  272.   my $x = $_[1];
  273.  
  274.   return 0+$x->[0] if scalar @$x == 1;  # below $BASE
  275.   my $fac = 1;
  276.   my $num = 0;
  277.   foreach (@$x)
  278.     {
  279.     $num += $fac*$_; $fac *= $BASE;
  280.     }
  281.   $num; 
  282.   }
  283.  
  284. ##############################################################################
  285. # actual math code
  286.  
  287. sub _add
  288.   {
  289.   # (ref to int_num_array, ref to int_num_array)
  290.   # routine to add two base 1eX numbers
  291.   # stolen from Knuth Vol 2 Algorithm A pg 231
  292.   # there are separate routines to add and sub as per Knuth pg 233
  293.   # This routine clobbers up array x, but not y.
  294.  
  295.   my ($c,$x,$y) = @_;
  296.  
  297.   return $x if (@$y == 1) && $y->[0] == 0;        # $x + 0 => $x
  298.   if ((@$x == 1) && $x->[0] == 0)            # 0 + $y => $y->copy
  299.     {
  300.     # twice as slow as $x = [ @$y ], but necc. to retain $x as ref :(
  301.     @$x = @$y; return $x;        
  302.     }
  303.  
  304.   # for each in Y, add Y to X and carry. If after that, something is left in
  305.   # X, foreach in X add carry to X and then return X, carry
  306.   # Trades one "$j++" for having to shift arrays
  307.   my $i; my $car = 0; my $j = 0;
  308.   for $i (@$y)
  309.     {
  310.     $x->[$j] -= $BASE if $car = (($x->[$j] += $i + $car) >= $BASE) ? 1 : 0;
  311.     $j++;
  312.     }
  313.   while ($car != 0)
  314.     {
  315.     $x->[$j] -= $BASE if $car = (($x->[$j] += $car) >= $BASE) ? 1 : 0; $j++;
  316.     }
  317.   $x;
  318.   }                                                                             
  319.  
  320. sub _inc
  321.   {
  322.   # (ref to int_num_array, ref to int_num_array)
  323.   # Add 1 to $x, modify $x in place
  324.   my ($c,$x) = @_;
  325.  
  326.   for my $i (@$x)
  327.     {
  328.     return $x if (($i += 1) < $BASE);        # early out
  329.     $i = 0;                    # overflow, next
  330.     }
  331.   push @$x,1 if ($x->[-1] == 0);        # last overflowed, so extend
  332.   $x;
  333.   }                                                                             
  334.  
  335. sub _dec
  336.   {
  337.   # (ref to int_num_array, ref to int_num_array)
  338.   # Sub 1 from $x, modify $x in place
  339.   my ($c,$x) = @_;
  340.  
  341.   my $MAX = $BASE-1;                # since MAX_VAL based on MBASE
  342.   for my $i (@$x)
  343.     {
  344.     last if (($i -= 1) >= 0);            # early out
  345.     $i = $MAX;                    # underflow, next
  346.     }
  347.   pop @$x if $x->[-1] == 0 && @$x > 1;        # last underflowed (but leave 0)
  348.   $x;
  349.   }                                                                             
  350.  
  351. sub _sub
  352.   {
  353.   # (ref to int_num_array, ref to int_num_array, swap)
  354.   # subtract base 1eX numbers -- stolen from Knuth Vol 2 pg 232, $x > $y
  355.   # subtract Y from X by modifying x in place
  356.   my ($c,$sx,$sy,$s) = @_;
  357.  
  358.   my $car = 0; my $i; my $j = 0;
  359.   if (!$s)
  360.     {
  361.     for $i (@$sx)
  362.       {
  363.       last unless defined $sy->[$j] || $car;
  364.       $i += $BASE if $car = (($i -= ($sy->[$j] || 0) + $car) < 0); $j++;
  365.       }
  366.     # might leave leading zeros, so fix that
  367.     return __strip_zeros($sx);
  368.     }
  369.   for $i (@$sx)
  370.     {
  371.     # we can't do an early out if $x is < than $y, since we
  372.     # need to copy the high chunks from $y. Found by Bob Mathews.
  373.     #last unless defined $sy->[$j] || $car;
  374.     $sy->[$j] += $BASE
  375.      if $car = (($sy->[$j] = $i-($sy->[$j]||0) - $car) < 0);
  376.     $j++;
  377.     }
  378.   # might leave leading zeros, so fix that
  379.   __strip_zeros($sy);
  380.   }                                                                             
  381.  
  382. sub _mul_use_mul
  383.   {
  384.   # (ref to int_num_array, ref to int_num_array)
  385.   # multiply two numbers in internal representation
  386.   # modifies first arg, second need not be different from first
  387.   my ($c,$xv,$yv) = @_;
  388.  
  389.   if (@$yv == 1)
  390.     {
  391.     # shortcut for two very short numbers (improved by Nathan Zook)
  392.     # works also if xv and yv are the same reference, and handles also $x == 0
  393.     if (@$xv == 1)
  394.       {
  395.       if (($xv->[0] *= $yv->[0]) >= $MBASE)
  396.          {
  397.          $xv->[0] = $xv->[0] - ($xv->[1] = int($xv->[0] * $RBASE)) * $MBASE;
  398.          };
  399.       return $xv;
  400.       }
  401.     # $x * 0 => 0
  402.     if ($yv->[0] == 0)
  403.       {
  404.       @$xv = (0);
  405.       return $xv;
  406.       }
  407.     # multiply a large number a by a single element one, so speed up
  408.     my $y = $yv->[0]; my $car = 0;
  409.     foreach my $i (@$xv)
  410.       {
  411.       $i = $i * $y + $car; $car = int($i * $RBASE); $i -= $car * $MBASE;
  412.       }
  413.     push @$xv, $car if $car != 0;
  414.     return $xv;
  415.     }
  416.   # shortcut for result $x == 0 => result = 0
  417.   return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) ); 
  418.  
  419.   # since multiplying $x with $x fails, make copy in this case
  420.   $yv = [@$xv] if $xv == $yv;    # same references?
  421.  
  422.   my @prod = (); my ($prod,$car,$cty,$xi,$yi);
  423.  
  424.   for $xi (@$xv)
  425.     {
  426.     $car = 0; $cty = 0;
  427.  
  428.     # slow variant
  429. #    for $yi (@$yv)
  430. #      {
  431. #      $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  432. #      $prod[$cty++] =
  433. #       $prod - ($car = int($prod * RBASE)) * $MBASE;  # see USE_MUL
  434. #      }
  435. #    $prod[$cty] += $car if $car; # need really to check for 0?
  436. #    $xi = shift @prod;
  437.  
  438.     # faster variant
  439.     # looping through this if $xi == 0 is silly - so optimize it away!
  440.     $xi = (shift @prod || 0), next if $xi == 0;
  441.     for $yi (@$yv)
  442.       {
  443.       $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  444. ##     this is actually a tad slower
  445. ##        $prod = $prod[$cty]; $prod += ($car + $xi * $yi);    # no ||0 here
  446.       $prod[$cty++] =
  447.        $prod - ($car = int($prod * $RBASE)) * $MBASE;  # see USE_MUL
  448.       }
  449.     $prod[$cty] += $car if $car; # need really to check for 0?
  450.     $xi = shift @prod || 0;    # || 0 makes v5.005_3 happy
  451.     }
  452.   push @$xv, @prod;
  453.   __strip_zeros($xv);
  454.   $xv;
  455.   }                                                                             
  456.  
  457. sub _mul_use_div
  458.   {
  459.   # (ref to int_num_array, ref to int_num_array)
  460.   # multiply two numbers in internal representation
  461.   # modifies first arg, second need not be different from first
  462.   my ($c,$xv,$yv) = @_;
  463.  
  464.   if (@$yv == 1)
  465.     {
  466.     # shortcut for two small numbers, also handles $x == 0
  467.     if (@$xv == 1)
  468.       {
  469.       # shortcut for two very short numbers (improved by Nathan Zook)
  470.       # works also if xv and yv are the same reference, and handles also $x == 0
  471.       if (($xv->[0] *= $yv->[0]) >= $MBASE)
  472.           {
  473.           $xv->[0] =
  474.               $xv->[0] - ($xv->[1] = int($xv->[0] / $MBASE)) * $MBASE;
  475.           };
  476.       return $xv;
  477.       }
  478.     # $x * 0 => 0
  479.     if ($yv->[0] == 0)
  480.       {
  481.       @$xv = (0);
  482.       return $xv;
  483.       }
  484.     # multiply a large number a by a single element one, so speed up
  485.     my $y = $yv->[0]; my $car = 0;
  486.     foreach my $i (@$xv)
  487.       {
  488.       $i = $i * $y + $car; $car = int($i / $MBASE); $i -= $car * $MBASE;
  489.       }
  490.     push @$xv, $car if $car != 0;
  491.     return $xv;
  492.     }
  493.   # shortcut for result $x == 0 => result = 0
  494.   return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) ); 
  495.  
  496.   # since multiplying $x with $x fails, make copy in this case
  497.   $yv = [@$xv] if $xv == $yv;    # same references?
  498.  
  499.   my @prod = (); my ($prod,$car,$cty,$xi,$yi);
  500.   for $xi (@$xv)
  501.     {
  502.     $car = 0; $cty = 0;
  503.     # looping through this if $xi == 0 is silly - so optimize it away!
  504.     $xi = (shift @prod || 0), next if $xi == 0;
  505.     for $yi (@$yv)
  506.       {
  507.       $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  508.       $prod[$cty++] =
  509.        $prod - ($car = int($prod / $MBASE)) * $MBASE;
  510.       }
  511.     $prod[$cty] += $car if $car; # need really to check for 0?
  512.     $xi = shift @prod || 0;    # || 0 makes v5.005_3 happy
  513.     }
  514.   push @$xv, @prod;
  515.   __strip_zeros($xv);
  516.   $xv;
  517.   }                                                                             
  518.  
  519. sub _div_use_mul
  520.   {
  521.   # ref to array, ref to array, modify first array and return remainder if 
  522.   # in list context
  523.  
  524.   # see comments in _div_use_div() for more explanations
  525.  
  526.   my ($c,$x,$yorg) = @_;
  527.   
  528.   # the general div algorithmn here is about O(N*N) and thus quite slow, so
  529.   # we first check for some special cases and use shortcuts to handle them.
  530.  
  531.   # This works, because we store the numbers in a chunked format where each
  532.   # element contains 5..7 digits (depending on system).
  533.  
  534.   # if both numbers have only one element:
  535.   if (@$x == 1 && @$yorg == 1)
  536.     {
  537.     # shortcut, $yorg and $x are two small numbers
  538.     if (wantarray)
  539.       {
  540.       my $r = [ $x->[0] % $yorg->[0] ];
  541.       $x->[0] = int($x->[0] / $yorg->[0]);
  542.       return ($x,$r); 
  543.       }
  544.     else
  545.       {
  546.       $x->[0] = int($x->[0] / $yorg->[0]);
  547.       return $x; 
  548.       }
  549.     }
  550.  
  551.   # if x has more than one, but y has only one element:
  552.   if (@$yorg == 1)
  553.     {
  554.     my $rem;
  555.     $rem = _mod($c,[ @$x ],$yorg) if wantarray;
  556.  
  557.     # shortcut, $y is < $BASE
  558.     my $j = scalar @$x; my $r = 0; 
  559.     my $y = $yorg->[0]; my $b;
  560.     while ($j-- > 0)
  561.       {
  562.       $b = $r * $MBASE + $x->[$j];
  563.       $x->[$j] = int($b/$y);
  564.       $r = $b % $y;
  565.       }
  566.     pop @$x if @$x > 1 && $x->[-1] == 0;    # splice up a leading zero 
  567.     return ($x,$rem) if wantarray;
  568.     return $x;
  569.     }
  570.  
  571.   # now x and y have more than one element
  572.  
  573.   # check whether y has more elements than x, if yet, the result will be 0
  574.   if (@$yorg > @$x)
  575.     {
  576.     my $rem;
  577.     $rem = [@$x] if wantarray;                  # make copy
  578.     splice (@$x,1);                             # keep ref to original array
  579.     $x->[0] = 0;                                # set to 0
  580.     return ($x,$rem) if wantarray;              # including remainder?
  581.     return $x;                    # only x, which is [0] now
  582.     }
  583.   # check whether the numbers have the same number of elements, in that case
  584.   # the result will fit into one element and can be computed efficiently
  585.   if (@$yorg == @$x)
  586.     {
  587.     my $rem;
  588.     # if $yorg has more digits than $x (it's leading element is longer than
  589.     # the one from $x), the result will also be 0:
  590.     if (length(int($yorg->[-1])) > length(int($x->[-1])))
  591.       {
  592.       $rem = [@$x] if wantarray;        # make copy
  593.       splice (@$x,1);                # keep ref to org array
  594.       $x->[0] = 0;                # set to 0
  595.       return ($x,$rem) if wantarray;        # including remainder?
  596.       return $x;
  597.       }
  598.     # now calculate $x / $yorg
  599.     if (length(int($yorg->[-1])) == length(int($x->[-1])))
  600.       {
  601.       # same length, so make full compare, and if equal, return 1
  602.       # hm, same lengths, but same contents? So we need to check all parts:
  603.       my $a = 0; my $j = scalar @$x - 1;
  604.       # manual way (abort if unequal, good for early ne)
  605.       while ($j >= 0)
  606.         {
  607.         last if ($a = $x->[$j] - $yorg->[$j]); $j--;
  608.         }
  609.       # $a contains the result of the compare between X and Y
  610.       # a < 0: x < y, a == 0 => x == y, a > 0: x > y
  611.       if ($a <= 0)
  612.         {
  613.         if (wantarray)
  614.       {
  615.           $rem = [ 0 ];            # a = 0 => x == y => rem 1
  616.           $rem = [@$x] if $a != 0;    # a < 0 => x < y => rem = x
  617.       }
  618.         splice(@$x,1);            # keep single element
  619.         $x->[0] = 0;            # if $a < 0
  620.         if ($a == 0)
  621.           {
  622.           # $x == $y
  623.           $x->[0] = 1;
  624.           }
  625.         return ($x,$rem) if wantarray;
  626.         return $x;
  627.         }
  628.       # $x >= $y, proceed normally
  629.       }
  630.     }
  631.  
  632.   # all other cases:
  633.  
  634.   my $y = [ @$yorg ];                # always make copy to preserve
  635.  
  636.   my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);
  637.  
  638.   $car = $bar = $prd = 0;
  639.   if (($dd = int($MBASE/($y->[-1]+1))) != 1) 
  640.     {
  641.     for $xi (@$x) 
  642.       {
  643.       $xi = $xi * $dd + $car;
  644.       $xi -= ($car = int($xi * $RBASE)) * $MBASE;    # see USE_MUL
  645.       }
  646.     push(@$x, $car); $car = 0;
  647.     for $yi (@$y) 
  648.       {
  649.       $yi = $yi * $dd + $car;
  650.       $yi -= ($car = int($yi * $RBASE)) * $MBASE;    # see USE_MUL
  651.       }
  652.     }
  653.   else 
  654.     {
  655.     push(@$x, 0);
  656.     }
  657.   @q = (); ($v2,$v1) = @$y[-2,-1];
  658.   $v2 = 0 unless $v2;
  659.   while ($#$x > $#$y) 
  660.     {
  661.     ($u2,$u1,$u0) = @$x[-3..-1];
  662.     $u2 = 0 unless $u2;
  663.     #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
  664.     # if $v1 == 0;
  665.     $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$MBASE+$u1)/$v1));
  666.     --$q while ($v2*$q > ($u0*$MBASE+$u1-$q*$v1)*$MBASE+$u2);
  667.     if ($q)
  668.       {
  669.       ($car, $bar) = (0,0);
  670.       for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) 
  671.         {
  672.         $prd = $q * $y->[$yi] + $car;
  673.         $prd -= ($car = int($prd * $RBASE)) * $MBASE;    # see USE_MUL
  674.     $x->[$xi] += $MBASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
  675.     }
  676.       if ($x->[-1] < $car + $bar) 
  677.         {
  678.         $car = 0; --$q;
  679.     for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) 
  680.           {
  681.       $x->[$xi] -= $MBASE
  682.        if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $MBASE));
  683.       }
  684.     }   
  685.       }
  686.     pop(@$x);
  687.     unshift(@q, $q);
  688.     }
  689.   if (wantarray) 
  690.     {
  691.     @d = ();
  692.     if ($dd != 1)  
  693.       {
  694.       $car = 0; 
  695.       for $xi (reverse @$x) 
  696.         {
  697.         $prd = $car * $MBASE + $xi;
  698.         $car = $prd - ($tmp = int($prd / $dd)) * $dd; # see USE_MUL
  699.         unshift(@d, $tmp);
  700.         }
  701.       }
  702.     else 
  703.       {
  704.       @d = @$x;
  705.       }
  706.     @$x = @q;
  707.     my $d = \@d; 
  708.     __strip_zeros($x);
  709.     __strip_zeros($d);
  710.     return ($x,$d);
  711.     }
  712.   @$x = @q;
  713.   __strip_zeros($x);
  714.   $x;
  715.   }
  716.  
  717. sub _div_use_div
  718.   {
  719.   # ref to array, ref to array, modify first array and return remainder if 
  720.   # in list context
  721.   my ($c,$x,$yorg) = @_;
  722.  
  723.   # the general div algorithmn here is about O(N*N) and thus quite slow, so
  724.   # we first check for some special cases and use shortcuts to handle them.
  725.  
  726.   # This works, because we store the numbers in a chunked format where each
  727.   # element contains 5..7 digits (depending on system).
  728.  
  729.   # if both numbers have only one element:
  730.   if (@$x == 1 && @$yorg == 1)
  731.     {
  732.     # shortcut, $yorg and $x are two small numbers
  733.     if (wantarray)
  734.       {
  735.       my $r = [ $x->[0] % $yorg->[0] ];
  736.       $x->[0] = int($x->[0] / $yorg->[0]);
  737.       return ($x,$r); 
  738.       }
  739.     else
  740.       {
  741.       $x->[0] = int($x->[0] / $yorg->[0]);
  742.       return $x; 
  743.       }
  744.     }
  745.   # if x has more than one, but y has only one element:
  746.   if (@$yorg == 1)
  747.     {
  748.     my $rem;
  749.     $rem = _mod($c,[ @$x ],$yorg) if wantarray;
  750.  
  751.     # shortcut, $y is < $BASE
  752.     my $j = scalar @$x; my $r = 0; 
  753.     my $y = $yorg->[0]; my $b;
  754.     while ($j-- > 0)
  755.       {
  756.       $b = $r * $MBASE + $x->[$j];
  757.       $x->[$j] = int($b/$y);
  758.       $r = $b % $y;
  759.       }
  760.     pop @$x if @$x > 1 && $x->[-1] == 0;    # splice up a leading zero 
  761.     return ($x,$rem) if wantarray;
  762.     return $x;
  763.     }
  764.   # now x and y have more than one element
  765.  
  766.   # check whether y has more elements than x, if yet, the result will be 0
  767.   if (@$yorg > @$x)
  768.     {
  769.     my $rem;
  770.     $rem = [@$x] if wantarray;            # make copy
  771.     splice (@$x,1);                # keep ref to original array
  772.     $x->[0] = 0;                # set to 0
  773.     return ($x,$rem) if wantarray;        # including remainder?
  774.     return $x;                    # only x, which is [0] now
  775.     }
  776.   # check whether the numbers have the same number of elements, in that case
  777.   # the result will fit into one element and can be computed efficiently
  778.   if (@$yorg == @$x)
  779.     {
  780.     my $rem;
  781.     # if $yorg has more digits than $x (it's leading element is longer than
  782.     # the one from $x), the result will also be 0:
  783.     if (length(int($yorg->[-1])) > length(int($x->[-1])))
  784.       {
  785.       $rem = [@$x] if wantarray;        # make copy
  786.       splice (@$x,1);                # keep ref to org array
  787.       $x->[0] = 0;                # set to 0
  788.       return ($x,$rem) if wantarray;        # including remainder?
  789.       return $x;
  790.       }
  791.     # now calculate $x / $yorg
  792.  
  793.     if (length(int($yorg->[-1])) == length(int($x->[-1])))
  794.       {
  795.       # same length, so make full compare, and if equal, return 1
  796.       # hm, same lengths, but same contents? So we need to check all parts:
  797.       my $a = 0; my $j = scalar @$x - 1;
  798.       # manual way (abort if unequal, good for early ne)
  799.       while ($j >= 0)
  800.         {
  801.         last if ($a = $x->[$j] - $yorg->[$j]); $j--;
  802.         }
  803.       # $a contains the result of the compare between X and Y
  804.       # a < 0: x < y, a == 0 => x == y, a > 0: x > y
  805.       if ($a <= 0)
  806.         {
  807.         if (wantarray)
  808.       {
  809.           $rem = [ 0 ];            # a = 0 => x == y => rem 1
  810.           $rem = [@$x] if $a != 0;    # a < 0 => x < y => rem = x
  811.       }
  812.         splice(@$x,1);            # keep single element
  813.         $x->[0] = 0;            # if $a < 0
  814.         if ($a == 0)
  815.           {
  816.           # $x == $y
  817.           $x->[0] = 1;
  818.           }
  819.         return ($x,$rem) if wantarray;
  820.         return $x;
  821.         }
  822.       # $x >= $y, so proceed normally
  823.       }
  824.     }
  825.  
  826.   # all other cases:
  827.  
  828.   my $y = [ @$yorg ];                # always make copy to preserve
  829.  
  830.   my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);
  831.  
  832.   $car = $bar = $prd = 0;
  833.   if (($dd = int($MBASE/($y->[-1]+1))) != 1) 
  834.     {
  835.     for $xi (@$x) 
  836.       {
  837.       $xi = $xi * $dd + $car;
  838.       $xi -= ($car = int($xi / $MBASE)) * $MBASE;
  839.       }
  840.     push(@$x, $car); $car = 0;
  841.     for $yi (@$y) 
  842.       {
  843.       $yi = $yi * $dd + $car;
  844.       $yi -= ($car = int($yi / $MBASE)) * $MBASE;
  845.       }
  846.     }
  847.   else 
  848.     {
  849.     push(@$x, 0);
  850.     }
  851.  
  852.   # @q will accumulate the final result, $q contains the current computed
  853.   # part of the final result
  854.  
  855.   @q = (); ($v2,$v1) = @$y[-2,-1];
  856.   $v2 = 0 unless $v2;
  857.   while ($#$x > $#$y) 
  858.     {
  859.     ($u2,$u1,$u0) = @$x[-3..-1];
  860.     $u2 = 0 unless $u2;
  861.     #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
  862.     # if $v1 == 0;
  863.     $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$MBASE+$u1)/$v1));
  864.     --$q while ($v2*$q > ($u0*$MBASE+$u1-$q*$v1)*$MBASE+$u2);
  865.     if ($q)
  866.       {
  867.       ($car, $bar) = (0,0);
  868.       for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) 
  869.         {
  870.         $prd = $q * $y->[$yi] + $car;
  871.         $prd -= ($car = int($prd / $MBASE)) * $MBASE;
  872.     $x->[$xi] += $MBASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
  873.     }
  874.       if ($x->[-1] < $car + $bar) 
  875.         {
  876.         $car = 0; --$q;
  877.     for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi) 
  878.           {
  879.       $x->[$xi] -= $MBASE
  880.        if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $MBASE));
  881.       }
  882.     }   
  883.       }
  884.     pop(@$x); unshift(@q, $q);
  885.     }
  886.   if (wantarray) 
  887.     {
  888.     @d = ();
  889.     if ($dd != 1)  
  890.       {
  891.       $car = 0; 
  892.       for $xi (reverse @$x) 
  893.         {
  894.         $prd = $car * $MBASE + $xi;
  895.         $car = $prd - ($tmp = int($prd / $dd)) * $dd;
  896.         unshift(@d, $tmp);
  897.         }
  898.       }
  899.     else 
  900.       {
  901.       @d = @$x;
  902.       }
  903.     @$x = @q;
  904.     my $d = \@d; 
  905.     __strip_zeros($x);
  906.     __strip_zeros($d);
  907.     return ($x,$d);
  908.     }
  909.   @$x = @q;
  910.   __strip_zeros($x);
  911.   $x;
  912.   }
  913.  
  914. ##############################################################################
  915. # testing
  916.  
  917. sub _acmp
  918.   {
  919.   # internal absolute post-normalized compare (ignore signs)
  920.   # ref to array, ref to array, return <0, 0, >0
  921.   # arrays must have at least one entry; this is not checked for
  922.   my ($c,$cx,$cy) = @_;
  923.  
  924.   # shortcut for short numbers 
  925.   return (($cx->[0] <=> $cy->[0]) <=> 0) 
  926.    if scalar @$cx == scalar @$cy && scalar @$cx == 1;
  927.  
  928.   # fast comp based on number of array elements (aka pseudo-length)
  929.   my $lxy = (scalar @$cx - scalar @$cy)
  930.   # or length of first element if same number of elements (aka difference 0)
  931.     ||
  932.   # need int() here because sometimes the last element is '00018' vs '18'
  933.    (length(int($cx->[-1])) - length(int($cy->[-1])));
  934.   return -1 if $lxy < 0;                # already differs, ret
  935.   return 1 if $lxy > 0;                    # ditto
  936.  
  937.   # manual way (abort if unequal, good for early ne)
  938.   my $a; my $j = scalar @$cx;
  939.   while (--$j >= 0)
  940.     {
  941.     last if ($a = $cx->[$j] - $cy->[$j]);
  942.     }
  943.   $a <=> 0;
  944.   }
  945.  
  946. sub _len
  947.   {
  948.   # compute number of digits
  949.  
  950.   # int() because add/sub sometimes leaves strings (like '00005') instead of
  951.   # '5' in this place, thus causing length() to report wrong length
  952.   my $cx = $_[1];
  953.  
  954.   (@$cx-1)*$BASE_LEN+length(int($cx->[-1]));
  955.   }
  956.  
  957. sub _digit
  958.   {
  959.   # return the nth digit, negative values count backward
  960.   # zero is rightmost, so _digit(123,0) will give 3
  961.   my ($c,$x,$n) = @_;
  962.  
  963.   my $len = _len('',$x);
  964.  
  965.   $n = $len+$n if $n < 0;        # -1 last, -2 second-to-last
  966.   $n = abs($n);                # if negative was too big
  967.   $len--; $n = $len if $n > $len;    # n to big?
  968.   
  969.   my $elem = int($n / $BASE_LEN);    # which array element
  970.   my $digit = $n % $BASE_LEN;        # which digit in this element
  971.   $elem = '0000'.@$x[$elem];        # get element padded with 0's
  972.   substr($elem,-$digit-1,1);
  973.   }
  974.  
  975. sub _zeros
  976.   {
  977.   # return amount of trailing zeros in decimal
  978.   # check each array elem in _m for having 0 at end as long as elem == 0
  979.   # Upon finding a elem != 0, stop
  980.   my $x = $_[1];
  981.  
  982.   return 0 if scalar @$x == 1 && $x->[0] == 0;
  983.  
  984.   my $zeros = 0; my $elem;
  985.   foreach my $e (@$x)
  986.     {
  987.     if ($e != 0)
  988.       {
  989.       $elem = "$e";                # preserve x
  990.       $elem =~ s/.*?(0*$)/$1/;            # strip anything not zero
  991.       $zeros *= $BASE_LEN;            # elems * 5
  992.       $zeros += length($elem);            # count trailing zeros
  993.       last;                    # early out
  994.       }
  995.     $zeros ++;                    # real else branch: 50% slower!
  996.     }
  997.   $zeros;
  998.   }
  999.  
  1000. ##############################################################################
  1001. # _is_* routines
  1002.  
  1003. sub _is_zero
  1004.   {
  1005.   # return true if arg is zero 
  1006.   (((scalar @{$_[1]} == 1) && ($_[1]->[0] == 0))) <=> 0;
  1007.   }
  1008.  
  1009. sub _is_even
  1010.   {
  1011.   # return true if arg is even
  1012.   (!($_[1]->[0] & 1)) <=> 0; 
  1013.   }
  1014.  
  1015. sub _is_odd
  1016.   {
  1017.   # return true if arg is even
  1018.   (($_[1]->[0] & 1)) <=> 0; 
  1019.   }
  1020.  
  1021. sub _is_one
  1022.   {
  1023.   # return true if arg is one
  1024.   (scalar @{$_[1]} == 1) && ($_[1]->[0] == 1) <=> 0; 
  1025.   }
  1026.  
  1027. sub _is_two
  1028.   {
  1029.   # return true if arg is two 
  1030.   (scalar @{$_[1]} == 1) && ($_[1]->[0] == 2) <=> 0; 
  1031.   }
  1032.  
  1033. sub _is_ten
  1034.   {
  1035.   # return true if arg is ten 
  1036.   (scalar @{$_[1]} == 1) && ($_[1]->[0] == 10) <=> 0; 
  1037.   }
  1038.  
  1039. sub __strip_zeros
  1040.   {
  1041.   # internal normalization function that strips leading zeros from the array
  1042.   # args: ref to array
  1043.   my $s = shift;
  1044.  
  1045.   my $cnt = scalar @$s; # get count of parts
  1046.   my $i = $cnt-1;
  1047.   push @$s,0 if $i < 0;        # div might return empty results, so fix it
  1048.  
  1049.   return $s if @$s == 1;        # early out
  1050.  
  1051.   #print "strip: cnt $cnt i $i\n";
  1052.   # '0', '3', '4', '0', '0',
  1053.   #  0    1    2    3    4
  1054.   # cnt = 5, i = 4
  1055.   # i = 4
  1056.   # i = 3
  1057.   # => fcnt = cnt - i (5-2 => 3, cnt => 5-1 = 4, throw away from 4th pos)
  1058.   # >= 1: skip first part (this can be zero)
  1059.   while ($i > 0) { last if $s->[$i] != 0; $i--; }
  1060.   $i++; splice @$s,$i if ($i < $cnt); # $i cant be 0
  1061.   $s;                                                                    
  1062.   }                                                                             
  1063.  
  1064. ###############################################################################
  1065. # check routine to test internal state for corruptions
  1066.  
  1067. sub _check
  1068.   {
  1069.   # used by the test suite
  1070.   my $x = $_[1];
  1071.  
  1072.   return "$x is not a reference" if !ref($x);
  1073.  
  1074.   # are all parts are valid?
  1075.   my $i = 0; my $j = scalar @$x; my ($e,$try);
  1076.   while ($i < $j)
  1077.     {
  1078.     $e = $x->[$i]; $e = 'undef' unless defined $e;
  1079.     $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e)";
  1080.     last if $e !~ /^[+]?[0-9]+$/;
  1081.     $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e) (stringify)";
  1082.     last if "$e" !~ /^[+]?[0-9]+$/;
  1083.     $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e) (cat-stringify)";
  1084.     last if '' . "$e" !~ /^[+]?[0-9]+$/;
  1085.     $try = ' < 0 || >= $BASE; '."($x, $e)";
  1086.     last if $e <0 || $e >= $BASE;
  1087.     # this test is disabled, since new/bnorm and certain ops (like early out
  1088.     # in add/sub) are allowed/expected to leave '00000' in some elements
  1089.     #$try = '=~ /^00+/; '."($x, $e)";
  1090.     #last if $e =~ /^00+/;
  1091.     $i++;
  1092.     }
  1093.   return "Illegal part '$e' at pos $i (tested: $try)" if $i < $j;
  1094.   0;
  1095.   }
  1096.  
  1097.  
  1098. ###############################################################################
  1099.  
  1100. sub _mod
  1101.   {
  1102.   # if possible, use mod shortcut
  1103.   my ($c,$x,$yo) = @_;
  1104.  
  1105.   # slow way since $y to big
  1106.   if (scalar @$yo > 1)
  1107.     {
  1108.     my ($xo,$rem) = _div($c,$x,$yo);
  1109.     return $rem;
  1110.     }
  1111.  
  1112.   my $y = $yo->[0];
  1113.   # both are single element arrays
  1114.   if (scalar @$x == 1)
  1115.     {
  1116.     $x->[0] %= $y;
  1117.     return $x;
  1118.     }
  1119.  
  1120.   # @y is a single element, but @x has more than one element
  1121.   my $b = $BASE % $y;
  1122.   if ($b == 0)
  1123.     {
  1124.     # when BASE % Y == 0 then (B * BASE) % Y == 0
  1125.     # (B * BASE) % $y + A % Y => A % Y
  1126.     # so need to consider only last element: O(1)
  1127.     $x->[0] %= $y;
  1128.     }
  1129.   elsif ($b == 1)
  1130.     {
  1131.     # else need to go through all elements: O(N), but loop is a bit simplified
  1132.     my $r = 0;
  1133.     foreach (@$x)
  1134.       {
  1135.       $r = ($r + $_) % $y;        # not much faster, but heh...
  1136.       #$r += $_ % $y; $r %= $y;
  1137.       }
  1138.     $r = 0 if $r == $y;
  1139.     $x->[0] = $r;
  1140.     }
  1141.   else
  1142.     {
  1143.     # else need to go through all elements: O(N)
  1144.     my $r = 0; my $bm = 1;
  1145.     foreach (@$x)
  1146.       {
  1147.       $r = ($_ * $bm + $r) % $y;
  1148.       $bm = ($bm * $b) % $y;
  1149.  
  1150.       #$r += ($_ % $y) * $bm;
  1151.       #$bm *= $b;
  1152.       #$bm %= $y;
  1153.       #$r %= $y;
  1154.       }
  1155.     $r = 0 if $r == $y;
  1156.     $x->[0] = $r;
  1157.     }
  1158.   splice (@$x,1);        # keep one element of $x
  1159.   $x;
  1160.   }
  1161.  
  1162. ##############################################################################
  1163. # shifts
  1164.  
  1165. sub _rsft
  1166.   {
  1167.   my ($c,$x,$y,$n) = @_;
  1168.  
  1169.   if ($n != 10)
  1170.     {
  1171.     $n = _new($c,$n); return _div($c,$x, _pow($c,$n,$y));
  1172.     }
  1173.  
  1174.   # shortcut (faster) for shifting by 10)
  1175.   # multiples of $BASE_LEN
  1176.   my $dst = 0;                # destination
  1177.   my $src = _num($c,$y);        # as normal int
  1178.   my $xlen = (@$x-1)*$BASE_LEN+length(int($x->[-1]));  # len of x in digits
  1179.   if ($src > $xlen or ($src == $xlen and ! defined $x->[1]))
  1180.     {
  1181.     # 12345 67890 shifted right by more than 10 digits => 0
  1182.     splice (@$x,1);                    # leave only one element
  1183.     $x->[0] = 0;                       # set to zero
  1184.     return $x;
  1185.     }
  1186.   my $rem = $src % $BASE_LEN;        # remainder to shift
  1187.   $src = int($src / $BASE_LEN);        # source
  1188.   if ($rem == 0)
  1189.     {
  1190.     splice (@$x,0,$src);        # even faster, 38.4 => 39.3
  1191.     }
  1192.   else
  1193.     {
  1194.     my $len = scalar @$x - $src;    # elems to go
  1195.     my $vd; my $z = '0'x $BASE_LEN;
  1196.     $x->[scalar @$x] = 0;        # avoid || 0 test inside loop
  1197.     while ($dst < $len)
  1198.       {
  1199.       $vd = $z.$x->[$src];
  1200.       $vd = substr($vd,-$BASE_LEN,$BASE_LEN-$rem);
  1201.       $src++;
  1202.       $vd = substr($z.$x->[$src],-$rem,$rem) . $vd;
  1203.       $vd = substr($vd,-$BASE_LEN,$BASE_LEN) if length($vd) > $BASE_LEN;
  1204.       $x->[$dst] = int($vd);
  1205.       $dst++;
  1206.       }
  1207.     splice (@$x,$dst) if $dst > 0;        # kill left-over array elems
  1208.     pop @$x if $x->[-1] == 0 && @$x > 1;    # kill last element if 0
  1209.     } # else rem == 0
  1210.   $x;
  1211.   }
  1212.  
  1213. sub _lsft
  1214.   {
  1215.   my ($c,$x,$y,$n) = @_;
  1216.  
  1217.   if ($n != 10)
  1218.     {
  1219.     $n = _new($c,$n); return _mul($c,$x, _pow($c,$n,$y));
  1220.     }
  1221.  
  1222.   # shortcut (faster) for shifting by 10) since we are in base 10eX
  1223.   # multiples of $BASE_LEN:
  1224.   my $src = scalar @$x;            # source
  1225.   my $len = _num($c,$y);        # shift-len as normal int
  1226.   my $rem = $len % $BASE_LEN;        # remainder to shift
  1227.   my $dst = $src + int($len/$BASE_LEN);    # destination
  1228.   my $vd;                # further speedup
  1229.   $x->[$src] = 0;            # avoid first ||0 for speed
  1230.   my $z = '0' x $BASE_LEN;
  1231.   while ($src >= 0)
  1232.     {
  1233.     $vd = $x->[$src]; $vd = $z.$vd;
  1234.     $vd = substr($vd,-$BASE_LEN+$rem,$BASE_LEN-$rem);
  1235.     $vd .= $src > 0 ? substr($z.$x->[$src-1],-$BASE_LEN,$rem) : '0' x $rem;
  1236.     $vd = substr($vd,-$BASE_LEN,$BASE_LEN) if length($vd) > $BASE_LEN;
  1237.     $x->[$dst] = int($vd);
  1238.     $dst--; $src--;
  1239.     }
  1240.   # set lowest parts to 0
  1241.   while ($dst >= 0) { $x->[$dst--] = 0; }
  1242.   # fix spurios last zero element
  1243.   splice @$x,-1 if $x->[-1] == 0;
  1244.   $x;
  1245.   }
  1246.  
  1247. sub _pow
  1248.   {
  1249.   # power of $x to $y
  1250.   # ref to array, ref to array, return ref to array
  1251.   my ($c,$cx,$cy) = @_;
  1252.  
  1253.   if (scalar @$cy == 1 && $cy->[0] == 0)
  1254.     {
  1255.     splice (@$cx,1); $cx->[0] = 1;        # y == 0 => x => 1
  1256.     return $cx;
  1257.     }
  1258.   if ((scalar @$cx == 1 && $cx->[0] == 1) ||    #    x == 1
  1259.       (scalar @$cy == 1 && $cy->[0] == 1))    # or y == 1
  1260.     {
  1261.     return $cx;
  1262.     }
  1263.   if (scalar @$cx == 1 && $cx->[0] == 0)
  1264.     {
  1265.     splice (@$cx,1); $cx->[0] = 0;        # 0 ** y => 0 (if not y <= 0)
  1266.     return $cx;
  1267.     }
  1268.  
  1269.   my $pow2 = _one();
  1270.  
  1271.   my $y_bin = _as_bin($c,$cy); $y_bin =~ s/^0b//;
  1272.   my $len = length($y_bin);
  1273.   while (--$len > 0)
  1274.     {
  1275.     _mul($c,$pow2,$cx) if substr($y_bin,$len,1) eq '1';        # is odd?
  1276.     _mul($c,$cx,$cx);
  1277.     }
  1278.  
  1279.   _mul($c,$cx,$pow2);
  1280.   $cx;
  1281.   }
  1282.  
  1283. sub _fac
  1284.   {
  1285.   # factorial of $x
  1286.   # ref to array, return ref to array
  1287.   my ($c,$cx) = @_;
  1288.  
  1289.   if ((@$cx == 1) && ($cx->[0] <= 2))
  1290.     {
  1291.     $cx->[0] ||= 1;        # 0 => 1, 1 => 1, 2 => 2
  1292.     return $cx;
  1293.     }
  1294.  
  1295.   # go forward until $base is exceeded
  1296.   # limit is either $x steps (steps == 100 means a result always too high) or
  1297.   # $base.
  1298.   my $steps = 100; $steps = $cx->[0] if @$cx == 1;
  1299.   my $r = 2; my $cf = 3; my $step = 2; my $last = $r;
  1300.   while ($r*$cf < $BASE && $step < $steps)
  1301.     {
  1302.     $last = $r; $r *= $cf++; $step++;
  1303.     }
  1304.   if ((@$cx == 1) && $step == $cx->[0])
  1305.     {
  1306.     # completely done, so keep reference to $x and return
  1307.     $cx->[0] = $r;
  1308.     return $cx;
  1309.     }
  1310.   
  1311.   # now we must do the left over steps
  1312.   my $n;                    # steps still to do
  1313.   if (scalar @$cx == 1)
  1314.     {
  1315.     $n = $cx->[0];
  1316.     }
  1317.   else
  1318.     {
  1319.     $n = _copy($c,$cx);
  1320.     }
  1321.  
  1322.   $cx->[0] = $last; splice (@$cx,1);        # keep ref to $x
  1323.   my $zero_elements = 0;
  1324.  
  1325.   # do left-over steps fit into a scalar?
  1326.   if (ref $n eq 'ARRAY')
  1327.     {
  1328.     # No, so use slower inc() & cmp()
  1329.     $step = [$step];
  1330.     while (_acmp($step,$n) <= 0)
  1331.       {
  1332.       # as soon as the last element of $cx is 0, we split it up and remember
  1333.       # how many zeors we got so far. The reason is that n! will accumulate
  1334.       # zeros at the end rather fast.
  1335.       if ($cx->[0] == 0)
  1336.         {
  1337.         $zero_elements ++; shift @$cx;
  1338.         }
  1339.       _mul($c,$cx,$step); _inc($c,$step);
  1340.       }
  1341.     }
  1342.   else
  1343.     {
  1344.     # Yes, so we can speed it up slightly
  1345.     while ($step <= $n)
  1346.       {
  1347.       # When the last element of $cx is 0, we split it up and remember
  1348.       # how many we got so far. The reason is that n! will accumulate
  1349.       # zeros at the end rather fast.
  1350.       if ($cx->[0] == 0)
  1351.         {
  1352.         $zero_elements ++; shift @$cx;
  1353.         }
  1354.       _mul($c,$cx,[$step]); $step++;
  1355.       }
  1356.     }
  1357.   # multiply in the zeros again
  1358.   while ($zero_elements-- > 0)
  1359.     {
  1360.     unshift @$cx, 0; 
  1361.     }
  1362.   $cx;            # return result
  1363.   }
  1364.  
  1365. #############################################################################
  1366.  
  1367. sub _log_int
  1368.   {
  1369.   # calculate integer log of $x to base $base
  1370.   # ref to array, ref to array - return ref to array
  1371.   my ($c,$x,$base) = @_;
  1372.  
  1373.   # X == 0 => NaN
  1374.   return if (scalar @$x == 1 && $x->[0] == 0);
  1375.   # BASE 0 or 1 => NaN
  1376.   return if (scalar @$base == 1 && $base->[0] < 2);
  1377.   my $cmp = _acmp($c,$x,$base); # X == BASE => 1
  1378.   if ($cmp == 0)
  1379.     {
  1380.     splice (@$x,1); $x->[0] = 1;
  1381.     return ($x,1)
  1382.     }
  1383.   # X < BASE
  1384.   if ($cmp < 0)
  1385.     {
  1386.     splice (@$x,1); $x->[0] = 0;
  1387.     return ($x,undef);
  1388.     }
  1389.  
  1390.   # this trial multiplication is very fast, even for large counts (like for
  1391.   # 2 ** 1024, since this still requires only 1024 very fast steps
  1392.   # (multiplication of a large number by a very small number is very fast))
  1393.   my $x_org = _copy($c,$x);        # preserve x
  1394.   splice(@$x,1); $x->[0] = 1;        # keep ref to $x
  1395.  
  1396.   my $trial = _copy($c,$base);
  1397.  
  1398.   # XXX TODO this only works if $base has only one element
  1399.   if (scalar @$base == 1)
  1400.     {
  1401.     # compute int ( length_in_base_10(X) / ( log(base) / log(10) ) )
  1402.     my $len = _len($c,$x_org);
  1403.     my $res = int($len / (log($base->[0]) / log(10))) || 1; # avoid $res == 0
  1404.  
  1405.     $x->[0] = $res;
  1406.     $trial = _pow ($c, _copy($c, $base), $x);
  1407.     my $a = _acmp($x,$trial,$x_org);
  1408.     return ($x,1) if $a == 0;
  1409.     # we now know that $res is too small
  1410.     if ($res < 0)
  1411.       {
  1412.       _mul($c,$trial,$base); _add($c, $x, [1]);
  1413.       }
  1414.     else
  1415.       {
  1416.       # or too big
  1417.       _div($c,$trial,$base); _sub($c, $x, [1]);
  1418.       }
  1419.     # did we now get the right result?
  1420.     $a = _acmp($x,$trial,$x_org);
  1421.     return ($x,1) if $a == 0;        # yes, exactly
  1422.     # still too big
  1423.     if ($a > 0)
  1424.       {
  1425.       _div($c,$trial,$base); _sub($c, $x, [1]);
  1426.       }
  1427.     } 
  1428.   
  1429.   # simple loop that increments $x by two in each step, possible overstepping
  1430.   # the real result by one
  1431.  
  1432.   my $a;
  1433.   my $base_mul = _mul($c, _copy($c,$base), $base);
  1434.  
  1435.   while (($a = _acmp($c,$trial,$x_org)) < 0)
  1436.     {
  1437.     _mul($c,$trial,$base_mul); _add($c, $x, [2]);
  1438.     }
  1439.  
  1440.   my $exact = 1;
  1441.   if ($a > 0)
  1442.     {
  1443.     # overstepped the result
  1444.     _dec($c, $x);
  1445.     _div($c,$trial,$base);
  1446.     $a = _acmp($c,$trial,$x_org);
  1447.     if ($a > 0)
  1448.       {
  1449.       _dec($c, $x);
  1450.       }
  1451.     $exact = 0 if $a != 0;
  1452.     }
  1453.   
  1454.   ($x,$exact);                # return result
  1455.   }
  1456.  
  1457. # for debugging:
  1458.   use constant DEBUG => 0;
  1459.   my $steps = 0;
  1460.   sub steps { $steps };
  1461.  
  1462. sub _sqrt
  1463.   {
  1464.   # square-root of $x in place
  1465.   # Compute a guess of the result (by rule of thumb), then improve it via
  1466.   # Newton's method.
  1467.   my ($c,$x) = @_;
  1468.  
  1469.   if (scalar @$x == 1)
  1470.     {
  1471.     # fit's into one Perl scalar, so result can be computed directly
  1472.     $x->[0] = int(sqrt($x->[0]));
  1473.     return $x;
  1474.     } 
  1475.   my $y = _copy($c,$x);
  1476.   # hopefully _len/2 is < $BASE, the -1 is to always undershot the guess
  1477.   # since our guess will "grow"
  1478.   my $l = int((_len($c,$x)-1) / 2);    
  1479.  
  1480.   my $lastelem = $x->[-1];                    # for guess
  1481.   my $elems = scalar @$x - 1;
  1482.   # not enough digits, but could have more?
  1483.   if ((length($lastelem) <= 3) && ($elems > 1))
  1484.     {
  1485.     # right-align with zero pad
  1486.     my $len = length($lastelem) & 1;
  1487.     print "$lastelem => " if DEBUG;
  1488.     $lastelem .= substr($x->[-2] . '0' x $BASE_LEN,0,$BASE_LEN);
  1489.     # former odd => make odd again, or former even to even again
  1490.     $lastelem = $lastelem / 10 if (length($lastelem) & 1) != $len;
  1491.     print "$lastelem\n" if DEBUG;
  1492.     }
  1493.  
  1494.   # construct $x (instead of _lsft($c,$x,$l,10)
  1495.   my $r = $l % $BASE_LEN;    # 10000 00000 00000 00000 ($BASE_LEN=5)
  1496.   $l = int($l / $BASE_LEN);
  1497.   print "l =  $l " if DEBUG;
  1498.  
  1499.   splice @$x,$l;        # keep ref($x), but modify it
  1500.  
  1501.   # we make the first part of the guess not '1000...0' but int(sqrt($lastelem))
  1502.   # that gives us:
  1503.   # 14400 00000 => sqrt(14400) => guess first digits to be 120
  1504.   # 144000 000000 => sqrt(144000) => guess 379
  1505.  
  1506.   print "$lastelem (elems $elems) => " if DEBUG;
  1507.   $lastelem = $lastelem / 10 if ($elems & 1 == 1);        # odd or even?
  1508.   my $g = sqrt($lastelem); $g =~ s/\.//;            # 2.345 => 2345
  1509.   $r -= 1 if $elems & 1 == 0;                    # 70 => 7
  1510.  
  1511.   # padd with zeros if result is too short
  1512.   $x->[$l--] = int(substr($g . '0' x $r,0,$r+1));
  1513.   print "now ",$x->[-1] if DEBUG;
  1514.   print " would have been ", int('1' . '0' x $r),"\n" if DEBUG;
  1515.  
  1516.   # If @$x > 1, we could compute the second elem of the guess, too, to create
  1517.   # an even better guess. Not implemented yet. Does it improve performance?
  1518.   $x->[$l--] = 0 while ($l >= 0);    # all other digits of guess are zero
  1519.  
  1520.   print "start x= ",_str($c,$x),"\n" if DEBUG;
  1521.   my $two = _two();
  1522.   my $last = _zero();
  1523.   my $lastlast = _zero();
  1524.   $steps = 0 if DEBUG;
  1525.   while (_acmp($c,$last,$x) != 0 && _acmp($c,$lastlast,$x) != 0)
  1526.     {
  1527.     $steps++ if DEBUG;
  1528.     $lastlast = _copy($c,$last);
  1529.     $last = _copy($c,$x);
  1530.     _add($c,$x, _div($c,_copy($c,$y),$x));
  1531.     _div($c,$x, $two );
  1532.     print " x= ",_str($c,$x),"\n" if DEBUG;
  1533.     }
  1534.   print "\nsteps in sqrt: $steps, " if DEBUG;
  1535.   _dec($c,$x) if _acmp($c,$y,_mul($c,_copy($c,$x),$x)) < 0;    # overshot? 
  1536.   print " final ",$x->[-1],"\n" if DEBUG;
  1537.   $x;
  1538.   }
  1539.  
  1540. sub _root
  1541.   {
  1542.   # take n'th root of $x in place (n >= 3)
  1543.   my ($c,$x,$n) = @_;
  1544.  
  1545.   if (scalar @$x == 1)
  1546.     {
  1547.     if (scalar @$n > 1)
  1548.       {
  1549.       # result will always be smaller than 2 so trunc to 1 at once
  1550.       $x->[0] = 1;
  1551.       }
  1552.     else
  1553.       {
  1554.       # fit's into one Perl scalar, so result can be computed directly
  1555.       # cannot use int() here, because it rounds wrongly (try 
  1556.       # (81 ** 3) ** (1/3) to see what I mean)
  1557.       #$x->[0] = int( $x->[0] ** (1 / $n->[0]) );
  1558.       # round to 8 digits, then truncate result to integer
  1559.       $x->[0] = int ( sprintf ("%.8f", $x->[0] ** (1 / $n->[0]) ) );
  1560.       }
  1561.     return $x;
  1562.     } 
  1563.  
  1564.   # we know now that X is more than one element long
  1565.  
  1566.   # if $n is a power of two, we can repeatedly take sqrt($X) and find the
  1567.   # proper result, because sqrt(sqrt($x)) == root($x,4)
  1568.   my $b = _as_bin($c,$n);
  1569.   if ($b =~ /0b1(0+)$/)
  1570.     {
  1571.     my $count = CORE::length($1);    # 0b100 => len('00') => 2
  1572.     my $cnt = $count;            # counter for loop
  1573.     unshift (@$x, 0);            # add one element, together with one
  1574.                     # more below in the loop this makes 2
  1575.     while ($cnt-- > 0)
  1576.       {
  1577.       # 'inflate' $X by adding one element, basically computing
  1578.       # $x * $BASE * $BASE. This gives us more $BASE_LEN digits for result
  1579.       # since len(sqrt($X)) approx == len($x) / 2.
  1580.       unshift (@$x, 0);
  1581.       # calculate sqrt($x), $x is now one element to big, again. In the next
  1582.       # round we make that two, again.
  1583.       _sqrt($c,$x);
  1584.       }
  1585.     # $x is now one element to big, so truncate result by removing it
  1586.     splice (@$x,0,1);
  1587.     } 
  1588.   else
  1589.     {
  1590.     # trial computation by starting with 2,4,8,16 etc until we overstep
  1591.     my $step;
  1592.     my $trial = _two();
  1593.  
  1594.     # while still to do more than X steps
  1595.     do
  1596.       {
  1597.       $step = _two();
  1598.       while (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) < 0)
  1599.         {
  1600.         _mul ($c, $step, [2]);
  1601.         _add ($c, $trial, $step);
  1602.         }
  1603.  
  1604.       # hit exactly?
  1605.       if (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) == 0)
  1606.         {
  1607.         @$x = @$trial;            # make copy while preserving ref to $x
  1608.         return $x;
  1609.         }
  1610.       # overstepped, so go back on step
  1611.       _sub($c, $trial, $step);
  1612.       } while (scalar @$step > 1 || $step->[0] > 128);
  1613.  
  1614.     # reset step to 2
  1615.     $step = _two();
  1616.     # add two, because $trial cannot be exactly the result (otherwise we would
  1617.     # alrady have found it)
  1618.     _add($c, $trial, $step);
  1619.  
  1620.     # and now add more and more (2,4,6,8,10 etc)
  1621.     while (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) < 0)
  1622.       {
  1623.       _add ($c, $trial, $step);
  1624.       }
  1625.  
  1626.     # hit not exactly? (overstepped)
  1627.     if (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) > 0)
  1628.       {
  1629.       _dec($c,$trial);
  1630.       }
  1631.  
  1632.     # hit not exactly? (overstepped)
  1633.     # 80 too small, 81 slightly too big, 82 too big
  1634.     if (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) > 0)
  1635.       {
  1636.       _dec ($c, $trial); 
  1637.       }
  1638.  
  1639.     @$x = @$trial;            # make copy while preserving ref to $x
  1640.     return $x;
  1641.     }
  1642.   $x; 
  1643.   }
  1644.  
  1645. ##############################################################################
  1646. # binary stuff
  1647.  
  1648. sub _and
  1649.   {
  1650.   my ($c,$x,$y) = @_;
  1651.  
  1652.   # the shortcut makes equal, large numbers _really_ fast, and makes only a
  1653.   # very small performance drop for small numbers (e.g. something with less
  1654.   # than 32 bit) Since we optimize for large numbers, this is enabled.
  1655.   return $x if _acmp($c,$x,$y) == 0;        # shortcut
  1656.   
  1657.   my $m = _one(); my ($xr,$yr);
  1658.   my $mask = $AND_MASK;
  1659.  
  1660.   my $x1 = $x;
  1661.   my $y1 = _copy($c,$y);            # make copy
  1662.   $x = _zero();
  1663.   my ($b,$xrr,$yrr);
  1664.   use integer;
  1665.   while (!_is_zero($c,$x1) && !_is_zero($c,$y1))
  1666.     {
  1667.     ($x1, $xr) = _div($c,$x1,$mask);
  1668.     ($y1, $yr) = _div($c,$y1,$mask);
  1669.  
  1670.     # make ints() from $xr, $yr
  1671.     # this is when the AND_BITS are greater than $BASE and is slower for
  1672.     # small (<256 bits) numbers, but faster for large numbers. Disabled
  1673.     # due to KISS principle
  1674.  
  1675. #    $b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; }
  1676. #    $b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; }
  1677. #    _add($c,$x, _mul($c, _new( $c, ($xrr & $yrr) ), $m) );
  1678.     
  1679.     # 0+ due to '&' doesn't work in strings
  1680.     _add($c,$x, _mul($c, [ 0+$xr->[0] & 0+$yr->[0] ], $m) );
  1681.     _mul($c,$m,$mask);
  1682.     }
  1683.   $x;
  1684.   }
  1685.  
  1686. sub _xor
  1687.   {
  1688.   my ($c,$x,$y) = @_;
  1689.  
  1690.   return _zero() if _acmp($c,$x,$y) == 0;    # shortcut (see -and)
  1691.  
  1692.   my $m = _one(); my ($xr,$yr);
  1693.   my $mask = $XOR_MASK;
  1694.  
  1695.   my $x1 = $x;
  1696.   my $y1 = _copy($c,$y);            # make copy
  1697.   $x = _zero();
  1698.   my ($b,$xrr,$yrr);
  1699.   use integer;
  1700.   while (!_is_zero($c,$x1) && !_is_zero($c,$y1))
  1701.     {
  1702.     ($x1, $xr) = _div($c,$x1,$mask);
  1703.     ($y1, $yr) = _div($c,$y1,$mask);
  1704.     # make ints() from $xr, $yr (see _and())
  1705.     #$b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; }
  1706.     #$b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; }
  1707.     #_add($c,$x, _mul($c, _new( $c, ($xrr ^ $yrr) ), $m) );
  1708.  
  1709.     # 0+ due to '^' doesn't work in strings
  1710.     _add($c,$x, _mul($c, [ 0+$xr->[0] ^ 0+$yr->[0] ], $m) );
  1711.     _mul($c,$m,$mask);
  1712.     }
  1713.   # the loop stops when the shorter of the two numbers is exhausted
  1714.   # the remainder of the longer one will survive bit-by-bit, so we simple
  1715.   # multiply-add it in
  1716.   _add($c,$x, _mul($c, $x1, $m) ) if !_is_zero($c,$x1);
  1717.   _add($c,$x, _mul($c, $y1, $m) ) if !_is_zero($c,$y1);
  1718.   
  1719.   $x;
  1720.   }
  1721.  
  1722. sub _or
  1723.   {
  1724.   my ($c,$x,$y) = @_;
  1725.  
  1726.   return $x if _acmp($c,$x,$y) == 0;        # shortcut (see _and)
  1727.  
  1728.   my $m = _one(); my ($xr,$yr);
  1729.   my $mask = $OR_MASK;
  1730.  
  1731.   my $x1 = $x;
  1732.   my $y1 = _copy($c,$y);            # make copy
  1733.   $x = _zero();
  1734.   my ($b,$xrr,$yrr);
  1735.   use integer;
  1736.   while (!_is_zero($c,$x1) && !_is_zero($c,$y1))
  1737.     {
  1738.     ($x1, $xr) = _div($c,$x1,$mask);
  1739.     ($y1, $yr) = _div($c,$y1,$mask);
  1740.     # make ints() from $xr, $yr (see _and())
  1741. #    $b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; }
  1742. #    $b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; }
  1743. #    _add($c,$x, _mul($c, _new( $c, ($xrr | $yrr) ), $m) );
  1744.     
  1745.     # 0+ due to '|' doesn't work in strings
  1746.     _add($c,$x, _mul($c, [ 0+$xr->[0] | 0+$yr->[0] ], $m) );
  1747.     _mul($c,$m,$mask);
  1748.     }
  1749.   # the loop stops when the shorter of the two numbers is exhausted
  1750.   # the remainder of the longer one will survive bit-by-bit, so we simple
  1751.   # multiply-add it in
  1752.   _add($c,$x, _mul($c, $x1, $m) ) if !_is_zero($c,$x1);
  1753.   _add($c,$x, _mul($c, $y1, $m) ) if !_is_zero($c,$y1);
  1754.   
  1755.   $x;
  1756.   }
  1757.  
  1758. sub _as_hex
  1759.   {
  1760.   # convert a decimal number to hex (ref to array, return ref to string)
  1761.   my ($c,$x) = @_;
  1762.  
  1763.   # fit's into one element (handle also 0x0 case)
  1764.   if (@$x == 1)
  1765.     {
  1766.     my $t = sprintf("0x%x",$x->[0]);
  1767.     return $t;
  1768.     }
  1769.  
  1770.   my $x1 = _copy($c,$x);
  1771.  
  1772.   my $es = '';
  1773.   my ($xr, $h, $x10000);
  1774.   if ($] >= 5.006)
  1775.     {
  1776.     $x10000 = [ 0x10000 ]; $h = 'h4';
  1777.     }
  1778.   else
  1779.     {
  1780.     $x10000 = [ 0x1000 ]; $h = 'h3';
  1781.     }
  1782.   # while (! _is_zero($c,$x1))
  1783.   while (@$x1 != 1 || $x1->[0] != 0)        # _is_zero()
  1784.     {
  1785.     ($x1, $xr) = _div($c,$x1,$x10000);
  1786.     $es .= unpack($h,pack('v',$xr->[0]));    # XXX TODO: why pack('v',...)?
  1787.     }
  1788.   $es = reverse $es;
  1789.   $es =~ s/^[0]+//;   # strip leading zeros
  1790.   $es = '0x' . $es;
  1791.   $es;
  1792.   }
  1793.  
  1794. sub _as_bin
  1795.   {
  1796.   # convert a decimal number to bin (ref to array, return ref to string)
  1797.   my ($c,$x) = @_;
  1798.  
  1799.   # fit's into one element (and Perl recent enough), handle also 0b0 case
  1800.   # handle zero case for older Perls
  1801.   if ($] <= 5.005 && @$x == 1 && $x->[0] == 0)
  1802.     {
  1803.     my $t = '0b0'; return $t;
  1804.     }
  1805.   if (@$x == 1 && $] >= 5.006)
  1806.     {
  1807.     my $t = sprintf("0b%b",$x->[0]);
  1808.     return $t;
  1809.     }
  1810.   my $x1 = _copy($c,$x);
  1811.  
  1812.   my $es = '';
  1813.   my ($xr, $b, $x10000);
  1814.   if ($] >= 5.006)
  1815.     {
  1816.     $x10000 = [ 0x10000 ]; $b = 'b16';
  1817.     }
  1818.   else
  1819.     {
  1820.     $x10000 = [ 0x1000 ]; $b = 'b12';
  1821.     }
  1822.   # while (! _is_zero($c,$x1))
  1823.   while (!(@$x1 == 1 && $x1->[0] == 0))        # _is_zero()
  1824.     {
  1825.     ($x1, $xr) = _div($c,$x1,$x10000);
  1826.     $es .= unpack($b,pack('v',$xr->[0]));    # XXX TODO: why pack('v',...)?
  1827.     # $es .= unpack($b,$xr->[0]);
  1828.     }
  1829.   $es = reverse $es;
  1830.   $es =~ s/^[0]+//;   # strip leading zeros
  1831.   $es = '0b' . $es;
  1832.   $es;
  1833.   }
  1834.  
  1835. sub _from_hex
  1836.   {
  1837.   # convert a hex number to decimal (ref to string, return ref to array)
  1838.   my ($c,$hs) = @_;
  1839.  
  1840.   my $mul = _one();
  1841.   my $m = [ 0x10000 ];                # 16 bit at a time
  1842.   my $x = _zero();
  1843.  
  1844.   my $len = length($hs)-2;
  1845.   $len = int($len/4);                # 4-digit parts, w/o '0x'
  1846.   my $val; my $i = -4;
  1847.   while ($len >= 0)
  1848.     {
  1849.     $val = substr($hs,$i,4);
  1850.     $val =~ s/^[+-]?0x// if $len == 0;        # for last part only because
  1851.     $val = hex($val);                # hex does not like wrong chars
  1852.     $i -= 4; $len --;
  1853.     _add ($c, $x, _mul ($c, [ $val ], $mul ) ) if $val != 0;
  1854.     _mul ($c, $mul, $m ) if $len >= 0;         # skip last mul
  1855.     }
  1856.   $x;
  1857.   }
  1858.  
  1859. sub _from_bin
  1860.   {
  1861.   # convert a hex number to decimal (ref to string, return ref to array)
  1862.   my ($c,$bs) = @_;
  1863.  
  1864.   # instead of converting X (8) bit at a time, it is faster to "convert" the
  1865.   # number to hex, and then call _from_hex.
  1866.  
  1867.   my $hs = $bs;
  1868.   $hs =~ s/^[+-]?0b//;                    # remove sign and 0b
  1869.   my $l = length($hs);                    # bits
  1870.   $hs = '0' x (8-($l % 8)) . $hs if ($l % 8) != 0;    # padd left side w/ 0
  1871.   my $h = unpack('H*', pack ('B*', $hs));        # repack as hex
  1872.   
  1873.   $c->_from_hex('0x'.$h);
  1874.   }
  1875.  
  1876. ##############################################################################
  1877. # special modulus functions
  1878.  
  1879. sub _modinv
  1880.   {
  1881.   # modular inverse
  1882.   my ($c,$x,$y) = @_;
  1883.  
  1884.   my $u = _zero($c); my $u1 = _one($c);
  1885.   my $a = _copy($c,$y); my $b = _copy($c,$x);
  1886.  
  1887.   # Euclid's Algorithm for bgcd(), only that we calc bgcd() ($a) and the
  1888.   # result ($u) at the same time. See comments in BigInt for why this works.
  1889.   my $q;
  1890.   ($a, $q, $b) = ($b, _div($c,$a,$b));        # step 1
  1891.   my $sign = 1;
  1892.   while (!_is_zero($c,$b))
  1893.     {
  1894.     my $t = _add($c,                 # step 2:
  1895.        _mul($c,_copy($c,$u1), $q) ,        #  t =  u1 * q
  1896.        $u );                    #     + u
  1897.     $u = $u1;                    #  u = u1, u1 = t
  1898.     $u1 = $t;
  1899.     $sign = -$sign;
  1900.     ($a, $q, $b) = ($b, _div($c,$a,$b));    # step 1
  1901.     }
  1902.  
  1903.   # if the gcd is not 1, then return NaN
  1904.   return (undef,undef) unless _is_one($c,$a);
  1905.  
  1906.   $sign = $sign == 1 ? '+' : '-';
  1907.   ($u1,$sign);
  1908.   }
  1909.  
  1910. sub _modpow
  1911.   {
  1912.   # modulus of power ($x ** $y) % $z
  1913.   my ($c,$num,$exp,$mod) = @_;
  1914.  
  1915.   # in the trivial case,
  1916.   if (_is_one($c,$mod))
  1917.     {
  1918.     splice @$num,0,1; $num->[0] = 0;
  1919.     return $num;
  1920.     }
  1921.   if ((scalar @$num == 1) && (($num->[0] == 0) || ($num->[0] == 1)))
  1922.     {
  1923.     $num->[0] = 1;
  1924.     return $num;
  1925.     }
  1926.  
  1927. #  $num = _mod($c,$num,$mod);    # this does not make it faster
  1928.  
  1929.   my $acc = _copy($c,$num); my $t = _one();
  1930.  
  1931.   my $expbin = _as_bin($c,$exp); $expbin =~ s/^0b//;
  1932.   my $len = length($expbin);
  1933.   while (--$len >= 0)
  1934.     {
  1935.     if ( substr($expbin,$len,1) eq '1')            # is_odd
  1936.       {
  1937.       _mul($c,$t,$acc);
  1938.       $t = _mod($c,$t,$mod);
  1939.       }
  1940.     _mul($c,$acc,$acc);
  1941.     $acc = _mod($c,$acc,$mod);
  1942.     }
  1943.   @$num = @$t;
  1944.   $num;
  1945.   }
  1946.  
  1947. sub _gcd
  1948.   {
  1949.   # greatest common divisor
  1950.   my ($c,$x,$y) = @_;
  1951.  
  1952.   while (! _is_zero($c,$y))
  1953.     {
  1954.     my $t = _copy($c,$y);
  1955.     $y = _mod($c, $x, $y);
  1956.     $x = $t;
  1957.     }
  1958.   $x;
  1959.   }
  1960.  
  1961. ##############################################################################
  1962. ##############################################################################
  1963.  
  1964. 1;
  1965. __END__
  1966.  
  1967. =head1 NAME
  1968.  
  1969. Math::BigInt::Calc - Pure Perl module to support Math::BigInt
  1970.  
  1971. =head1 SYNOPSIS
  1972.  
  1973. Provides support for big integer calculations. Not intended to be used by other
  1974. modules. Other modules which sport the same functions can also be used to support
  1975. Math::BigInt, like Math::BigInt::GMP or Math::BigInt::Pari.
  1976.  
  1977. =head1 DESCRIPTION
  1978.  
  1979. In order to allow for multiple big integer libraries, Math::BigInt was
  1980. rewritten to use library modules for core math routines. Any module which
  1981. follows the same API as this can be used instead by using the following:
  1982.  
  1983.     use Math::BigInt lib => 'libname';
  1984.  
  1985. 'libname' is either the long name ('Math::BigInt::Pari'), or only the short
  1986. version like 'Pari'.
  1987.  
  1988. =head1 STORAGE
  1989.  
  1990. =head1 METHODS
  1991.  
  1992. The following functions MUST be defined in order to support the use by
  1993. Math::BigInt v1.70 or later:
  1994.  
  1995.     api_version()    return API version, minimum 1 for v1.70
  1996.     _new(string)    return ref to new object from ref to decimal string
  1997.     _zero()        return a new object with value 0
  1998.     _one()        return a new object with value 1
  1999.     _two()        return a new object with value 2
  2000.     _ten()        return a new object with value 10
  2001.  
  2002.     _str(obj)    return ref to a string representing the object
  2003.     _num(obj)    returns a Perl integer/floating point number
  2004.             NOTE: because of Perl numeric notation defaults,
  2005.             the _num'ified obj may lose accuracy due to 
  2006.             machine-dependend floating point size limitations
  2007.                     
  2008.     _add(obj,obj)    Simple addition of two objects
  2009.     _mul(obj,obj)    Multiplication of two objects
  2010.     _div(obj,obj)    Division of the 1st object by the 2nd
  2011.             In list context, returns (result,remainder).
  2012.             NOTE: this is integer math, so no
  2013.             fractional part will be returned.
  2014.             The second operand will be not be 0, so no need to
  2015.             check for that.
  2016.     _sub(obj,obj)    Simple subtraction of 1 object from another
  2017.             a third, optional parameter indicates that the params
  2018.             are swapped. In this case, the first param needs to
  2019.             be preserved, while you can destroy the second.
  2020.             sub (x,y,1) => return x - y and keep x intact!
  2021.     _dec(obj)    decrement object by one (input is garant. to be > 0)
  2022.     _inc(obj)    increment object by one
  2023.  
  2024.  
  2025.     _acmp(obj,obj)    <=> operator for objects (return -1, 0 or 1)
  2026.  
  2027.     _len(obj)    returns count of the decimal digits of the object
  2028.     _digit(obj,n)    returns the n'th decimal digit of object
  2029.  
  2030.     _is_one(obj)    return true if argument is 1
  2031.     _is_two(obj)    return true if argument is 2
  2032.     _is_ten(obj)    return true if argument is 10
  2033.     _is_zero(obj)    return true if argument is 0
  2034.     _is_even(obj)    return true if argument is even (0,2,4,6..)
  2035.     _is_odd(obj)    return true if argument is odd (1,3,5,7..)
  2036.  
  2037.     _copy        return a ref to a true copy of the object
  2038.  
  2039.     _check(obj)    check whether internal representation is still intact
  2040.             return 0 for ok, otherwise error message as string
  2041.  
  2042.     _from_hex(str)    return ref to new object from ref to hexadecimal string
  2043.     _from_bin(str)    return ref to new object from ref to binary string
  2044.     
  2045.     _as_hex(str)    return string containing the value as
  2046.             unsigned hex string, with the '0x' prepended.
  2047.             Leading zeros must be stripped.
  2048.     _as_bin(str)    Like as_hex, only as binary string containing only
  2049.             zeros and ones. Leading zeros must be stripped and a
  2050.             '0b' must be prepended.
  2051.     
  2052.     _rsft(obj,N,B)    shift object in base B by N 'digits' right
  2053.     _lsft(obj,N,B)    shift object in base B by N 'digits' left
  2054.     
  2055.     _xor(obj1,obj2)    XOR (bit-wise) object 1 with object 2
  2056.             Note: XOR, AND and OR pad with zeros if size mismatches
  2057.     _and(obj1,obj2)    AND (bit-wise) object 1 with object 2
  2058.     _or(obj1,obj2)    OR (bit-wise) object 1 with object 2
  2059.  
  2060.     _mod(obj,obj)    Return remainder of div of the 1st by the 2nd object
  2061.     _sqrt(obj)    return the square root of object (truncated to int)
  2062.     _root(obj)    return the n'th (n >= 3) root of obj (truncated to int)
  2063.     _fac(obj)    return factorial of object 1 (1*2*3*4..)
  2064.     _pow(obj,obj)    return object 1 to the power of object 2
  2065.             return undef for NaN
  2066.     _zeros(obj)    return number of trailing decimal zeros
  2067.     _modinv        return inverse modulus
  2068.     _modpow        return modulus of power ($x ** $y) % $z
  2069.     _log_int(X,N)    calculate integer log() of X in base N
  2070.             X >= 0, N >= 0 (return undef for NaN)
  2071.             returns (RESULT, EXACT) where EXACT is:
  2072.              1     : result is exactly RESULT
  2073.              0     : result was truncated to RESULT
  2074.              undef : unknown whether result is exactly RESULT
  2075.         _gcd(obj,obj)    return Greatest Common Divisor of two objects
  2076.  
  2077. The following functions are optional, and can be defined if the underlying lib
  2078. has a fast way to do them. If undefined, Math::BigInt will use pure Perl (hence
  2079. slow) fallback routines to emulate these:
  2080.     
  2081.     _signed_or
  2082.     _signed_and
  2083.     _signed_xor
  2084.  
  2085.  
  2086. Input strings come in as unsigned but with prefix (i.e. as '123', '0xabc'
  2087. or '0b1101').
  2088.  
  2089. So the library needs only to deal with unsigned big integers. Testing of input
  2090. parameter validity is done by the caller, so you need not worry about
  2091. underflow (f.i. in C<_sub()>, C<_dec()>) nor about division by zero or similar
  2092. cases.
  2093.  
  2094. The first parameter can be modified, that includes the possibility that you
  2095. return a reference to a completely different object instead. Although keeping
  2096. the reference and just changing it's contents is prefered over creating and
  2097. returning a different reference.
  2098.  
  2099. Return values are always references to objects, strings, or true/false for
  2100. comparisation routines.
  2101.  
  2102. =head1 WRAP YOUR OWN
  2103.  
  2104. If you want to port your own favourite c-lib for big numbers to the
  2105. Math::BigInt interface, you can take any of the already existing modules as
  2106. a rough guideline. You should really wrap up the latest BigInt and BigFloat
  2107. testsuites with your module, and replace in them any of the following:
  2108.  
  2109.     use Math::BigInt;
  2110.  
  2111. by this:
  2112.  
  2113.     use Math::BigInt lib => 'yourlib';
  2114.  
  2115. This way you ensure that your library really works 100% within Math::BigInt.
  2116.  
  2117. =head1 LICENSE
  2118.  
  2119. This program is free software; you may redistribute it and/or modify it under
  2120. the same terms as Perl itself. 
  2121.  
  2122. =head1 AUTHORS
  2123.  
  2124. Original math code by Mark Biggar, rewritten by Tels L<http://bloodgate.com/>
  2125. in late 2000.
  2126. Seperated from BigInt and shaped API with the help of John Peacock.
  2127. Fixed, sped-up and enhanced by Tels http://bloodgate.com 2001-2003.
  2128. Further streamlining (api_version 1) by Tels 2004.
  2129.  
  2130. =head1 SEE ALSO
  2131.  
  2132. L<Math::BigInt>, L<Math::BigFloat>, L<Math::BigInt::BitVect>,
  2133. L<Math::BigInt::GMP>, L<Math::BigInt::FastCalc> and L<Math::BigInt::Pari>.
  2134.  
  2135. =cut
  2136.