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