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