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