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