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