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