source: for-distributions/trunk/bin/windows/perl/lib/Math/BigInt/Calc.pm@ 14489

Last change on this file since 14489 was 14489, checked in by oranfry, 17 years ago

upgrading to perl 5.8

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