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