Math::Big* test tweaks to work better with core:
[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
dccbb853 11$VERSION = '0.13';
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
16# leading zero parts (except the first) and in base 100000
17
18# todo:
19# - fully remove funky $# stuff (maybe)
0716bf9b 20
21# USE_MUL: due to problems on certain os (os390, posix-bc) "* 1e-5" is used
ee15d750 22# instead of "/ 1e5" at some places, (marked with USE_MUL). Other platforms
23# BS2000, some Crays need USE_DIV instead.
bd05a461 24# The BEGIN block is used to determine which of the two variants gives the
25# correct result.
0716bf9b 26
27##############################################################################
28# global constants, flags and accessory
29
30# constants for easier life
31my $nan = 'NaN';
ee15d750 32my ($BASE,$RBASE,$BASE_LEN,$MAX_VAL);
33
34sub _base_len
35 {
dccbb853 36 # set/get the BASE_LEN and assorted other, connected values
37 # used only be the testsuite, set is used only by the BEGIN block below
ee15d750 38 my $b = shift;
39 if (defined $b)
40 {
dccbb853 41 $b = 8 if $b > 8; # cap, for VMS, OS/390 and other 64 bit
ee15d750 42 $BASE_LEN = $b;
43 $BASE = int("1e".$BASE_LEN);
44 $RBASE = abs('1e-'.$BASE_LEN); # see USE_MUL
45 $MAX_VAL = $BASE-1;
46 # print "BASE_LEN: $BASE_LEN MAX_VAL: $MAX_VAL\n";
47 # print "int: ",int($BASE * $RBASE),"\n";
48 if (int($BASE * $RBASE) == 0) # should be 1
49 {
50 # must USE_MUL
ee15d750 51 *{_mul} = \&_mul_use_mul;
52 *{_div} = \&_div_use_mul;
53 }
54 else
55 {
ee15d750 56 # can USE_DIV instead
57 *{_mul} = \&_mul_use_div;
58 *{_div} = \&_div_use_div;
59 }
60 }
dccbb853 61 $BASE_LEN;
ee15d750 62 }
574bacfe 63
64BEGIN
65 {
bd05a461 66 # from Daniel Pfeiffer: determine largest group of digits that is precisely
574bacfe 67 # multipliable with itself plus carry
dccbb853 68 # Test now changed to expect the proper pattern, not a result off by 1 or 2
69 my ($e, $num) = 3; # lowest value we will use is 3+1-1 = 3
bd05a461 70 do
71 {
72 $num = ('9' x ++$e) + 0;
574bacfe 73 $num *= $num + 1;
dccbb853 74 # print "$num $e\n";
75 } while ("$num" =~ /9{$e}0{$e}/); # must be a certain pattern
76 # last test failed, so retract one step:
ee15d750 77 _base_len($e-1);
574bacfe 78 }
79
0716bf9b 80##############################################################################
81# create objects from various representations
82
83sub _new
84 {
85 # (string) return ref to num_array
86 # Convert a number from string format to internal base 100000 format.
87 # Assumes normalized value as input.
574bacfe 88 my $d = $_[1];
0716bf9b 89 # print "_new $d $$d\n";
90 my $il = CORE::length($$d)-1;
91 # these leaves '00000' instead of int 0 and will be corrected after any op
574bacfe 92 return [ reverse(unpack("a" . ($il % $BASE_LEN+1)
93 . ("a$BASE_LEN" x ($il / $BASE_LEN)), $$d)) ];
0716bf9b 94 }
95
96sub _zero
97 {
98 # create a zero
99 return [ 0 ];
100 }
101
102sub _one
103 {
104 # create a one
105 return [ 1 ];
106 }
107
108sub _copy
109 {
574bacfe 110 return [ @{$_[1]} ];
0716bf9b 111 }
112
bd05a461 113# catch and throw away
114sub import { }
115
0716bf9b 116##############################################################################
117# convert back to string and number
118
119sub _str
120 {
121 # (ref to BINT) return num_str
122 # Convert number from internal base 100000 format to string format.
123 # internal format is always normalized (no leading zeros, "-0" => "+0")
574bacfe 124 my $ar = $_[1];
0716bf9b 125 my $ret = "";
126 my $l = scalar @$ar; # number of parts
127 return $nan if $l < 1; # should not happen
128 # handle first one different to strip leading zeros from it (there are no
129 # leading zero parts in internal representation)
130 $l --; $ret .= $ar->[$l]; $l--;
131 # Interestingly, the pre-padd method uses more time
574bacfe 132 # the old grep variant takes longer (14 to 10 sec)
133 my $z = '0' x ($BASE_LEN-1);
0716bf9b 134 while ($l >= 0)
135 {
574bacfe 136 $ret .= substr($z.$ar->[$l],-$BASE_LEN); # fastest way I could think of
0716bf9b 137 $l--;
138 }
139 return \$ret;
140 }
141
142sub _num
143 {
144 # Make a number (scalar int/float) from a BigInt object
574bacfe 145 my $x = $_[1];
0716bf9b 146 return $x->[0] if scalar @$x == 1; # below $BASE
147 my $fac = 1;
148 my $num = 0;
149 foreach (@$x)
150 {
151 $num += $fac*$_; $fac *= $BASE;
152 }
153 return $num;
154 }
155
156##############################################################################
157# actual math code
158
159sub _add
160 {
161 # (ref to int_num_array, ref to int_num_array)
574bacfe 162 # routine to add two base 1eX numbers
0716bf9b 163 # stolen from Knuth Vol 2 Algorithm A pg 231
b22b3e31 164 # there are separate routines to add and sub as per Knuth pg 233
0716bf9b 165 # This routine clobbers up array x, but not y.
166
574bacfe 167 my ($c,$x,$y) = @_;
0716bf9b 168
169 # for each in Y, add Y to X and carry. If after that, something is left in
170 # X, foreach in X add carry to X and then return X, carry
171 # Trades one "$j++" for having to shift arrays, $j could be made integer
b22b3e31 172 # but this would impose a limit to number-length of 2**32.
0716bf9b 173 my $i; my $car = 0; my $j = 0;
174 for $i (@$y)
175 {
176 $x->[$j] -= $BASE
177 if $car = (($x->[$j] += $i + $car) >= $BASE) ? 1 : 0;
178 $j++;
179 }
180 while ($car != 0)
181 {
182 $x->[$j] -= $BASE if $car = (($x->[$j] += $car) >= $BASE) ? 1 : 0; $j++;
183 }
184 return $x;
185 }
186
187sub _sub
188 {
189 # (ref to int_num_array, ref to int_num_array)
574bacfe 190 # subtract base 1eX numbers -- stolen from Knuth Vol 2 pg 232, $x > $y
b22b3e31 191 # subtract Y from X (X is always greater/equal!) by modifying x in place
574bacfe 192 my ($c,$sx,$sy,$s) = @_;
0716bf9b 193
194 my $car = 0; my $i; my $j = 0;
195 if (!$s)
196 {
197 #print "case 2\n";
198 for $i (@$sx)
199 {
200 last unless defined $sy->[$j] || $car;
201 #print "x: $i y: $sy->[$j] c: $car\n";
202 $i += $BASE if $car = (($i -= ($sy->[$j] || 0) + $car) < 0); $j++;
203 #print "x: $i y: $sy->[$j-1] c: $car\n";
204 }
205 # might leave leading zeros, so fix that
206 __strip_zeros($sx);
207 return $sx;
208 }
209 else
210 {
211 #print "case 1 (swap)\n";
212 for $i (@$sx)
213 {
214 last unless defined $sy->[$j] || $car;
215 #print "$sy->[$j] $i $car => $sx->[$j]\n";
216 $sy->[$j] += $BASE
217 if $car = (($sy->[$j] = $i-($sy->[$j]||0) - $car) < 0);
218 #print "$sy->[$j] $i $car => $sy->[$j]\n";
219 $j++;
220 }
221 # might leave leading zeros, so fix that
222 __strip_zeros($sy);
223 return $sy;
224 }
225 }
226
ee15d750 227sub _mul_use_mul
0716bf9b 228 {
229 # (BINT, BINT) return nothing
230 # multiply two numbers in internal representation
b22b3e31 231 # modifies first arg, second need not be different from first
574bacfe 232 my ($c,$xv,$yv) = @_;
dccbb853 233
0716bf9b 234 my @prod = (); my ($prod,$car,$cty,$xi,$yi);
235 # since multiplying $x with $x fails, make copy in this case
574bacfe 236 $yv = [@$xv] if "$xv" eq "$yv"; # same references?
0716bf9b 237 for $xi (@$xv)
238 {
239 $car = 0; $cty = 0;
574bacfe 240
241 # slow variant
242# for $yi (@$yv)
243# {
244# $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
245# $prod[$cty++] =
246# $prod - ($car = int($prod * RBASE)) * $BASE; # see USE_MUL
247# }
248# $prod[$cty] += $car if $car; # need really to check for 0?
249# $xi = shift @prod;
250
251 # faster variant
252 # looping through this if $xi == 0 is silly - so optimize it away!
253 $xi = (shift @prod || 0), next if $xi == 0;
0716bf9b 254 for $yi (@$yv)
255 {
256 $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
574bacfe 257## this is actually a tad slower
258## $prod = $prod[$cty]; $prod += ($car + $xi * $yi); # no ||0 here
0716bf9b 259 $prod[$cty++] =
574bacfe 260 $prod - ($car = int($prod * $RBASE)) * $BASE; # see USE_MUL
0716bf9b 261 }
262 $prod[$cty] += $car if $car; # need really to check for 0?
263 $xi = shift @prod;
264 }
0716bf9b 265 push @$xv, @prod;
266 __strip_zeros($xv);
267 # normalize (handled last to save check for $y->is_zero()
268 return $xv;
269 }
270
ee15d750 271sub _mul_use_div
272 {
273 # (BINT, BINT) return nothing
274 # multiply two numbers in internal representation
275 # modifies first arg, second need not be different from first
276 my ($c,$xv,$yv) = @_;
277
278 my @prod = (); my ($prod,$car,$cty,$xi,$yi);
279 # since multiplying $x with $x fails, make copy in this case
280 $yv = [@$xv] if "$xv" eq "$yv"; # same references?
281 for $xi (@$xv)
282 {
283 $car = 0; $cty = 0;
284 # looping through this if $xi == 0 is silly - so optimize it away!
285 $xi = (shift @prod || 0), next if $xi == 0;
286 for $yi (@$yv)
287 {
288 $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
289 $prod[$cty++] =
290 $prod - ($car = int($prod / $BASE)) * $BASE;
291 }
292 $prod[$cty] += $car if $car; # need really to check for 0?
293 $xi = shift @prod;
294 }
295 push @$xv, @prod;
296 __strip_zeros($xv);
297 # normalize (handled last to save check for $y->is_zero()
298 return $xv;
299 }
300
301sub _div_use_mul
0716bf9b 302 {
b22b3e31 303 # ref to array, ref to array, modify first array and return remainder if
0716bf9b 304 # in list context
b22b3e31 305 # no longer handles sign
574bacfe 306 my ($c,$x,$yorg) = @_;
0716bf9b 307 my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1);
308
309 my (@d,$tmp,$q,$u2,$u1,$u0);
310
311 $car = $bar = $prd = 0;
312
313 my $y = [ @$yorg ];
314 if (($dd = int($BASE/($y->[-1]+1))) != 1)
315 {
316 for $xi (@$x)
317 {
318 $xi = $xi * $dd + $car;
319 $xi -= ($car = int($xi * $RBASE)) * $BASE; # see USE_MUL
320 }
321 push(@$x, $car); $car = 0;
322 for $yi (@$y)
323 {
324 $yi = $yi * $dd + $car;
325 $yi -= ($car = int($yi * $RBASE)) * $BASE; # see USE_MUL
326 }
327 }
328 else
329 {
330 push(@$x, 0);
331 }
332 @q = (); ($v2,$v1) = @$y[-2,-1];
333 $v2 = 0 unless $v2;
334 while ($#$x > $#$y)
335 {
336 ($u2,$u1,$u0) = @$x[-3..-1];
337 $u2 = 0 unless $u2;
338 #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
339 # if $v1 == 0;
ee15d750 340 # $q = (($u0 == $v1) ? 99999 : int(($u0*$BASE+$u1)/$v1));
341 $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$BASE+$u1)/$v1));
574bacfe 342 --$q while ($v2*$q > ($u0*$BASE+$u1-$q*$v1)*$BASE+$u2);
0716bf9b 343 if ($q)
344 {
345 ($car, $bar) = (0,0);
346 for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
347 {
348 $prd = $q * $y->[$yi] + $car;
349 $prd -= ($car = int($prd * $RBASE)) * $BASE; # see USE_MUL
574bacfe 350 $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
0716bf9b 351 }
352 if ($x->[-1] < $car + $bar)
353 {
354 $car = 0; --$q;
355 for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
356 {
574bacfe 357 $x->[$xi] -= $BASE
0716bf9b 358 if ($car = (($x->[$xi] += $y->[$yi] + $car) > $BASE));
359 }
360 }
361 }
362 pop(@$x); unshift(@q, $q);
363 }
364 if (wantarray)
365 {
366 @d = ();
367 if ($dd != 1)
368 {
369 $car = 0;
370 for $xi (reverse @$x)
371 {
372 $prd = $car * $BASE + $xi;
373 $car = $prd - ($tmp = int($prd / $dd)) * $dd; # see USE_MUL
374 unshift(@d, $tmp);
375 }
376 }
377 else
378 {
379 @d = @$x;
380 }
381 @$x = @q;
382 __strip_zeros($x);
383 __strip_zeros(\@d);
384 return ($x,\@d);
385 }
386 @$x = @q;
387 __strip_zeros($x);
388 return $x;
389 }
390
ee15d750 391sub _div_use_div
392 {
393 # ref to array, ref to array, modify first array and return remainder if
394 # in list context
395 # no longer handles sign
396 my ($c,$x,$yorg) = @_;
397 my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1);
398
399 my (@d,$tmp,$q,$u2,$u1,$u0);
400
401 $car = $bar = $prd = 0;
402
403 my $y = [ @$yorg ];
404 if (($dd = int($BASE/($y->[-1]+1))) != 1)
405 {
406 for $xi (@$x)
407 {
408 $xi = $xi * $dd + $car;
409 $xi -= ($car = int($xi / $BASE)) * $BASE;
410 }
411 push(@$x, $car); $car = 0;
412 for $yi (@$y)
413 {
414 $yi = $yi * $dd + $car;
415 $yi -= ($car = int($yi / $BASE)) * $BASE;
416 }
417 }
418 else
419 {
420 push(@$x, 0);
421 }
422 @q = (); ($v2,$v1) = @$y[-2,-1];
423 $v2 = 0 unless $v2;
424 while ($#$x > $#$y)
425 {
426 ($u2,$u1,$u0) = @$x[-3..-1];
427 $u2 = 0 unless $u2;
428 #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
429 # if $v1 == 0;
430 # $q = (($u0 == $v1) ? 99999 : int(($u0*$BASE+$u1)/$v1));
431 $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$BASE+$u1)/$v1));
432 --$q while ($v2*$q > ($u0*$BASE+$u1-$q*$v1)*$BASE+$u2);
433 if ($q)
434 {
435 ($car, $bar) = (0,0);
436 for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
437 {
438 $prd = $q * $y->[$yi] + $car;
439 $prd -= ($car = int($prd / $BASE)) * $BASE;
440 $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
441 }
442 if ($x->[-1] < $car + $bar)
443 {
444 $car = 0; --$q;
445 for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
446 {
447 $x->[$xi] -= $BASE
448 if ($car = (($x->[$xi] += $y->[$yi] + $car) > $BASE));
449 }
450 }
451 }
452 pop(@$x); unshift(@q, $q);
453 }
454 if (wantarray)
455 {
456 @d = ();
457 if ($dd != 1)
458 {
459 $car = 0;
460 for $xi (reverse @$x)
461 {
462 $prd = $car * $BASE + $xi;
463 $car = $prd - ($tmp = int($prd / $dd)) * $dd;
464 unshift(@d, $tmp);
465 }
466 }
467 else
468 {
469 @d = @$x;
470 }
471 @$x = @q;
472 __strip_zeros($x);
473 __strip_zeros(\@d);
474 return ($x,\@d);
475 }
476 @$x = @q;
477 __strip_zeros($x);
478 return $x;
479 }
480
dccbb853 481sub _mod
482 {
483 # if possible, use mod shortcut
484 my ($c,$x,$yo) = @_;
485
486 # slow way since $y to big
487 if (scalar @$yo > 1)
488 {
489 my ($xo,$rem) = _div($c,$x,$yo);
490 return $rem;
491 }
492 my $y = $yo->[0];
493 # both are single element
494 if (scalar @$x == 1)
495 {
496 $x->[0] %= $y;
497 return $x;
498 }
499
500 my $b = $BASE % $y;
501 if ($b == 0)
502 {
503 # when BASE % Y == 0 then (B * BASE) % Y == 0
504 # (B * BASE) % $y + A % Y => A % Y
505 # so need to consider only last element: O(1)
506 $x->[0] %= $y;
507 }
508 else
509 {
510 # else need to go trough all elemens: O(N)
511 # XXX not ready yet
512 my ($xo,$rem) = _div($c,$x,$yo);
513 return $rem;
514
515# my $i = 0; my $r = 1;
516# print "Multi: ";
517# foreach (@$x)
518# {
519# print "$_ $r $b $y\n";
520# print "\$_ % \$y = ",$_ % $y,"\n";
521# print "\$_ % \$y * \$b = ",($_ % $y) * $b,"\n";
522# $r += ($_ % $y) * $b;
523# print "$r $b $y =>";
524# $r %= $y if $r > $y;
525# print " $r\n";
526# }
527# $x->[0] = $r;
528 }
529 splice (@$x,1);
530 return $x;
531 }
532
0716bf9b 533##############################################################################
574bacfe 534# shifts
535
536sub _rsft
537 {
538 my ($c,$x,$y,$n) = @_;
539
540 if ($n != 10)
541 {
542 return; # we cant do this here, due to now _pow, so signal failure
543 }
544 else
545 {
546 # shortcut (faster) for shifting by 10)
547 # multiples of $BASE_LEN
548 my $dst = 0; # destination
549 my $src = _num($c,$y); # as normal int
dccbb853 550 my $rem = $src % $BASE_LEN; # remainder to shift
574bacfe 551 $src = int($src / $BASE_LEN); # source
552 if ($rem == 0)
553 {
554 splice (@$x,0,$src); # even faster, 38.4 => 39.3
555 }
556 else
557 {
558 my $len = scalar @$x - $src; # elems to go
559 my $vd; my $z = '0'x $BASE_LEN;
560 $x->[scalar @$x] = 0; # avoid || 0 test inside loop
561 while ($dst < $len)
562 {
563 $vd = $z.$x->[$src];
564 #print "$dst $src '$vd' ";
565 $vd = substr($vd,-$BASE_LEN,$BASE_LEN-$rem);
566 #print "'$vd' ";
567 $src++;
568 $vd = substr($z.$x->[$src],-$rem,$rem) . $vd;
569 #print "'$vd1' ";
570 #print "'$vd'\n";
571 $vd = substr($vd,-$BASE_LEN,$BASE_LEN) if length($vd) > $BASE_LEN;
572 $x->[$dst] = int($vd);
573 $dst++;
574 }
575 splice (@$x,$dst) if $dst > 0; # kill left-over array elems
576 pop @$x if $x->[-1] == 0; # kill last element if 0
577 } # else rem == 0
578 }
579 $x;
580 }
581
582sub _lsft
583 {
584 my ($c,$x,$y,$n) = @_;
585
586 if ($n != 10)
587 {
588 return; # we cant do this here, due to now _pow, so signal failure
589 }
590 else
591 {
592 # shortcut (faster) for shifting by 10) since we are in base 10eX
593 # multiples of $BASE_LEN:
594 my $src = scalar @$x; # source
595 my $len = _num($c,$y); # shift-len as normal int
dccbb853 596 my $rem = $len % $BASE_LEN; # remainder to shift
574bacfe 597 my $dst = $src + int($len/$BASE_LEN); # destination
598 my $vd; # further speedup
599 #print "src $src:",$x->[$src]||0," dst $dst:",$v->[$dst]||0," rem $rem\n";
600 $x->[$src] = 0; # avoid first ||0 for speed
601 my $z = '0' x $BASE_LEN;
602 while ($src >= 0)
603 {
604 $vd = $x->[$src]; $vd = $z.$vd;
605 #print "s $src d $dst '$vd' ";
606 $vd = substr($vd,-$BASE_LEN+$rem,$BASE_LEN-$rem);
607 #print "'$vd' ";
608 $vd .= $src > 0 ? substr($z.$x->[$src-1],-$BASE_LEN,$rem) : '0' x $rem;
609 #print "'$vd' ";
610 $vd = substr($vd,-$BASE_LEN,$BASE_LEN) if length($vd) > $BASE_LEN;
611 #print "'$vd'\n";
612 $x->[$dst] = int($vd);
613 $dst--; $src--;
614 }
615 # set lowest parts to 0
616 while ($dst >= 0) { $x->[$dst--] = 0; }
617 # fix spurios last zero element
618 splice @$x,-1 if $x->[-1] == 0;
619 #print "elems: "; my $i = 0;
620 #foreach (reverse @$v) { print "$i $_ "; $i++; } print "\n";
621 }
622 $x;
623 }
624
625##############################################################################
0716bf9b 626# testing
627
628sub _acmp
629 {
630 # internal absolute post-normalized compare (ignore signs)
631 # ref to array, ref to array, return <0, 0, >0
b22b3e31 632 # arrays must have at least one entry; this is not checked for
0716bf9b 633
574bacfe 634 my ($c,$cx, $cy) = @_;
0716bf9b 635
636 #print "$cx $cy\n";
637 my ($i,$a,$x,$y,$k);
638 # calculate length based on digits, not parts
574bacfe 639 $x = _len('',$cx); $y = _len('',$cy);
0716bf9b 640 # print "length: ",($x-$y),"\n";
574bacfe 641 my $lxy = $x - $y; # if different in length
642 return -1 if $lxy < 0;
643 return 1 if $lxy > 0;
0716bf9b 644 #print "full compare\n";
645 $i = 0; $a = 0;
646 # first way takes 5.49 sec instead of 4.87, but has the early out advantage
b22b3e31 647 # so grep is slightly faster, but more inflexible. hm. $_ instead of $k
0716bf9b 648 # yields 5.6 instead of 5.5 sec huh?
649 # manual way (abort if unequal, good for early ne)
650 my $j = scalar @$cx - 1;
651 while ($j >= 0)
652 {
653 # print "$cx->[$j] $cy->[$j] $a",$cx->[$j]-$cy->[$j],"\n";
654 last if ($a = $cx->[$j] - $cy->[$j]); $j--;
655 }
574bacfe 656 return 1 if $a > 0;
657 return -1 if $a < 0;
658 return 0; # equal
0716bf9b 659 # while it early aborts, it is even slower than the manual variant
660 #grep { return $a if ($a = $_ - $cy->[$i++]); } @$cx;
661 # grep way, go trough all (bad for early ne)
662 #grep { $a = $_ - $cy->[$i++]; } @$cx;
663 #return $a;
664 }
665
666sub _len
667 {
dccbb853 668 # compute number of digits in bigint, minus the sign
b22b3e31 669 # int() because add/sub sometimes leaves strings (like '00005') instead of
dccbb853 670 # int ('5') in this place, thus causing length() to report wrong length
574bacfe 671 my $cx = $_[1];
0716bf9b 672
574bacfe 673 return (@$cx-1)*$BASE_LEN+length(int($cx->[-1]));
0716bf9b 674 }
675
676sub _digit
677 {
678 # return the nth digit, negative values count backward
679 # zero is rightmost, so _digit(123,0) will give 3
574bacfe 680 my ($c,$x,$n) = @_;
0716bf9b 681
574bacfe 682 my $len = _len('',$x);
0716bf9b 683
684 $n = $len+$n if $n < 0; # -1 last, -2 second-to-last
685 $n = abs($n); # if negative was too big
686 $len--; $n = $len if $n > $len; # n to big?
687
574bacfe 688 my $elem = int($n / $BASE_LEN); # which array element
689 my $digit = $n % $BASE_LEN; # which digit in this element
0716bf9b 690 $elem = '0000'.@$x[$elem]; # get element padded with 0's
691 return substr($elem,-$digit-1,1);
692 }
693
694sub _zeros
695 {
696 # return amount of trailing zeros in decimal
697 # check each array elem in _m for having 0 at end as long as elem == 0
698 # Upon finding a elem != 0, stop
574bacfe 699 my $x = $_[1];
0716bf9b 700 my $zeros = 0; my $elem;
701 foreach my $e (@$x)
702 {
703 if ($e != 0)
704 {
574bacfe 705 $elem = "$e"; # preserve x
706 $elem =~ s/.*?(0*$)/$1/; # strip anything not zero
707 $zeros *= $BASE_LEN; # elems * 5
708 $zeros += CORE::length($elem); # count trailing zeros
709 last; # early out
0716bf9b 710 }
574bacfe 711 $zeros ++; # real else branch: 50% slower!
0716bf9b 712 }
713 return $zeros;
714 }
715
716##############################################################################
717# _is_* routines
718
719sub _is_zero
720 {
721 # return true if arg (BINT or num_str) is zero (array '+', '0')
574bacfe 722 my $x = $_[1];
0716bf9b 723 return (((scalar @$x == 1) && ($x->[0] == 0))) <=> 0;
724 }
725
726sub _is_even
727 {
728 # return true if arg (BINT or num_str) is even
574bacfe 729 my $x = $_[1];
0716bf9b 730 return (!($x->[0] & 1)) <=> 0;
731 }
732
733sub _is_odd
734 {
735 # return true if arg (BINT or num_str) is even
574bacfe 736 my $x = $_[1];
0716bf9b 737 return (($x->[0] & 1)) <=> 0;
738 }
739
740sub _is_one
741 {
742 # return true if arg (BINT or num_str) is one (array '+', '1')
574bacfe 743 my $x = $_[1];
0716bf9b 744 return (scalar @$x == 1) && ($x->[0] == 1) <=> 0;
745 }
746
747sub __strip_zeros
748 {
749 # internal normalization function that strips leading zeros from the array
750 # args: ref to array
0716bf9b 751 my $s = shift;
752
753 my $cnt = scalar @$s; # get count of parts
754 my $i = $cnt-1;
755 #print "strip: cnt $cnt i $i\n";
756 # '0', '3', '4', '0', '0',
757 # 0 1 2 3 4
758 # cnt = 5, i = 4
759 # i = 4
760 # i = 3
761 # => fcnt = cnt - i (5-2 => 3, cnt => 5-1 = 4, throw away from 4th pos)
762 # >= 1: skip first part (this can be zero)
763 while ($i > 0) { last if $s->[$i] != 0; $i--; }
764 $i++; splice @$s,$i if ($i < $cnt); # $i cant be 0
765 return $s;
766 }
767
768###############################################################################
769# check routine to test internal state of corruptions
770
771sub _check
772 {
bd05a461 773 # used by the test suite
574bacfe 774 my $x = $_[1];
0716bf9b 775
0716bf9b 776 return "$x is not a reference" if !ref($x);
777
778 # are all parts are valid?
779 my $i = 0; my $j = scalar @$x; my ($e,$try);
780 while ($i < $j)
781 {
782 $e = $x->[$i]; $e = 'undef' unless defined $e;
783 $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e)";
784 last if $e !~ /^[+]?[0-9]+$/;
dccbb853 785 $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e) (stringify)";
786 last if "$e" !~ /^[+]?[0-9]+$/;
787 $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e) (cat-stringify)";
788 last if '' . "$e" !~ /^[+]?[0-9]+$/;
0716bf9b 789 $try = ' < 0 || >= $BASE; '."($x, $e)";
790 last if $e <0 || $e >= $BASE;
791 # this test is disabled, since new/bnorm and certain ops (like early out
792 # in add/sub) are allowed/expected to leave '00000' in some elements
793 #$try = '=~ /^00+/; '."($x, $e)";
794 #last if $e =~ /^00+/;
795 $i++;
796 }
797 return "Illegal part '$e' at pos $i (tested: $try)" if $i < $j;
798 return 0;
799 }
800
8011;
802__END__
803
804=head1 NAME
805
806Math::BigInt::Calc - Pure Perl module to support Math::BigInt
807
808=head1 SYNOPSIS
809
ee15d750 810Provides support for big integer calculations. Not intended to be used by other
811modules (except Math::BigInt::Cached). Other modules which sport the same
812functions can also be used to support Math::Bigint, like Math::BigInt::Pari.
0716bf9b 813
814=head1 DESCRIPTION
815
816In order to allow for multiple big integer libraries, Math::BigInt
817was rewritten to use library modules for core math routines. Any
818module which follows the same API as this can be used instead by
819using the following call:
820
ee15d750 821 use Math::BigInt lib => 'libname';
0716bf9b 822
823=head1 EXPORT
824
bd05a461 825The following functions MUST be defined in order to support
0716bf9b 826the use by Math::BigInt:
827
828 _new(string) return ref to new object from ref to decimal string
829 _zero() return a new object with value 0
830 _one() return a new object with value 1
831
832 _str(obj) return ref to a string representing the object
833 _num(obj) returns a Perl integer/floating point number
834 NOTE: because of Perl numeric notation defaults,
835 the _num'ified obj may lose accuracy due to
836 machine-dependend floating point size limitations
837
838 _add(obj,obj) Simple addition of two objects
839 _mul(obj,obj) Multiplication of two objects
840 _div(obj,obj) Division of the 1st object by the 2nd
b22b3e31 841 In list context, returns (result,remainder).
842 NOTE: this is integer math, so no
843 fractional part will be returned.
844 _sub(obj,obj) Simple subtraction of 1 object from another
0716bf9b 845 a third, optional parameter indicates that the params
846 are swapped. In this case, the first param needs to
847 be preserved, while you can destroy the second.
848 sub (x,y,1) => return x - y and keep x intact!
849
850 _acmp(obj,obj) <=> operator for objects (return -1, 0 or 1)
851
852 _len(obj) returns count of the decimal digits of the object
853 _digit(obj,n) returns the n'th decimal digit of object
854
855 _is_one(obj) return true if argument is +1
856 _is_zero(obj) return true if argument is 0
857 _is_even(obj) return true if argument is even (0,2,4,6..)
858 _is_odd(obj) return true if argument is odd (1,3,5,7..)
859
860 _copy return a ref to a true copy of the object
861
862 _check(obj) check whether internal representation is still intact
863 return 0 for ok, otherwise error message as string
864
bd05a461 865The following functions are optional, and can be defined if the underlying lib
ee15d750 866has a fast way to do them. If undefined, Math::BigInt will use a pure, but
bd05a461 867slow, Perl way as fallback to emulate these:
0716bf9b 868
869 _from_hex(str) return ref to new object from ref to hexadecimal string
870 _from_bin(str) return ref to new object from ref to binary string
871
ee15d750 872 _as_hex(str) return ref to scalar string containing the value as
873 unsigned hex string, with the '0x' prepended.
874 Leading zeros must be stripped.
875 _as_bin(str) Like as_hex, only as binary string containing only
876 zeros and ones. Leading zeros must be stripped and a
877 '0b' must be prepended.
878
0716bf9b 879 _rsft(obj,N,B) shift object in base B by N 'digits' right
dccbb853 880 For unsupported bases B, return undef to signal failure
0716bf9b 881 _lsft(obj,N,B) shift object in base B by N 'digits' left
dccbb853 882 For unsupported bases B, return undef to signal failure
0716bf9b 883
884 _xor(obj1,obj2) XOR (bit-wise) object 1 with object 2
dccbb853 885 Note: XOR, AND and OR pad with zeros if size mismatches
0716bf9b 886 _and(obj1,obj2) AND (bit-wise) object 1 with object 2
887 _or(obj1,obj2) OR (bit-wise) object 1 with object 2
888
dccbb853 889 _mod(obj,obj) Return remainder of div of the 1st by the 2nd object
0716bf9b 890 _sqrt(obj) return the square root of object
891 _pow(obj,obj) return object 1 to the power of object 2
892 _gcd(obj,obj) return Greatest Common Divisor of two objects
893
b22b3e31 894 _zeros(obj) return number of trailing decimal zeros
0716bf9b 895
896 _dec(obj) decrement object by one (input is >= 1)
897 _inc(obj) increment object by one
898
b22b3e31 899Input strings come in as unsigned but with prefix (i.e. as '123', '0xabc'
0716bf9b 900or '0b1101').
901
b22b3e31 902Testing of input parameter validity is done by the caller, so you need not
574bacfe 903worry about underflow (f.i. in C<_sub()>, C<_dec()>) nor about division by
904zero or similar cases.
905
906The first parameter can be modified, that includes the possibility that you
907return a reference to a completely different object instead. Although keeping
dccbb853 908the reference and just changing it's contents is prefered over creating and
909returning a different reference.
574bacfe 910
911Return values are always references to objects or strings. Exceptions are
912C<_lsft()> and C<_rsft()>, which return undef if they can not shift the
913argument. This is used to delegate shifting of bases different than 10 back
dccbb853 914to Math::BigInt, which will use some generic code to calculate the result.
574bacfe 915
916=head1 WRAP YOUR OWN
917
918If you want to port your own favourite c-lib for big numbers to the
919Math::BigInt interface, you can take any of the already existing modules as
920a rough guideline. You should really wrap up the latest BigInt and BigFloat
bd05a461 921testsuites with your module, and replace in them any of the following:
574bacfe 922
923 use Math::BigInt;
924
bd05a461 925by this:
574bacfe 926
927 use Math::BigInt lib => 'yourlib';
928
929This way you ensure that your library really works 100% within Math::BigInt.
0716bf9b 930
931=head1 LICENSE
932
933This program is free software; you may redistribute it and/or modify it under
934the same terms as Perl itself.
935
936=head1 AUTHORS
937
938Original math code by Mark Biggar, rewritten by Tels L<http://bloodgate.com/>
939in late 2000, 2001.
940Seperated from BigInt and shaped API with the help of John Peacock.
941
942=head1 SEE ALSO
943
ee15d750 944L<Math::BigInt>, L<Math::BigFloat>, L<Math::BigInt::BitVect>,
945L<Math::BigInt::GMP>, L<Math::BigInt::Cached> and L<Math::BigInt::Pari>.
0716bf9b 946
947=cut