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