1package Math::BigInt::Calc; 2 3use 5.006001; 4use strict; 5use warnings; 6 7use Carp; 8use Math::BigInt::Lib; 9 10our $VERSION = '1.999811'; 11 12our @ISA = ('Math::BigInt::Lib'); 13 14# Package to store unsigned big integers in decimal and do math with them 15 16# Internally the numbers are stored in an array with at least 1 element, no 17# leading zero parts (except the first) and in base 1eX where X is determined 18# automatically at loading time to be the maximum possible value 19 20# todo: 21# - fully remove funky $# stuff in div() (maybe - that code scares me...) 22 23# USE_MUL: due to problems on certain os (os390, posix-bc) "* 1e-5" is used 24# instead of "/ 1e5" at some places, (marked with USE_MUL). Other platforms 25# BS2000, some Crays need USE_DIV instead. 26# The BEGIN block is used to determine which of the two variants gives the 27# correct result. 28 29# Beware of things like: 30# $i = $i * $y + $car; $car = int($i / $BASE); $i = $i % $BASE; 31# This works on x86, but fails on ARM (SA1100, iPAQ) due to who knows what 32# reasons. So, use this instead (slower, but correct): 33# $i = $i * $y + $car; $car = int($i / $BASE); $i -= $BASE * $car; 34 35############################################################################## 36# global constants, flags and accessory 37 38# announce that we are compatible with MBI v1.83 and up 39sub api_version () { 2; } 40 41# constants for easier life 42my ($BASE, $BASE_LEN, $RBASE, $MAX_VAL); 43my ($AND_BITS, $XOR_BITS, $OR_BITS); 44my ($AND_MASK, $XOR_MASK, $OR_MASK); 45 46sub _base_len { 47 # Set/get the BASE_LEN and assorted other, related values. 48 # Used only by the testsuite, the set variant is used only by the BEGIN 49 # block below: 50 51 my ($class, $b, $int) = @_; 52 if (defined $b) { 53 # avoid redefinitions 54 undef &_mul; 55 undef &_div; 56 57 if ($] >= 5.008 && $int && $b > 7) { 58 $BASE_LEN = $b; 59 *_mul = \&_mul_use_div_64; 60 *_div = \&_div_use_div_64; 61 $BASE = int("1e" . $BASE_LEN); 62 $MAX_VAL = $BASE-1; 63 return $BASE_LEN unless wantarray; 64 return ($BASE_LEN, $BASE, $AND_BITS, $XOR_BITS, $OR_BITS, $BASE_LEN, $MAX_VAL); 65 } 66 67 # find whether we can use mul or div in mul()/div() 68 $BASE_LEN = $b + 1; 69 my $caught = 0; 70 while (--$BASE_LEN > 5) { 71 $BASE = int("1e" . $BASE_LEN); 72 $RBASE = abs('1e-' . $BASE_LEN); # see USE_MUL 73 $caught = 0; 74 $caught += 1 if (int($BASE * $RBASE) != 1); # should be 1 75 $caught += 2 if (int($BASE / $BASE) != 1); # should be 1 76 last if $caught != 3; 77 } 78 $BASE = int("1e" . $BASE_LEN); 79 $RBASE = abs('1e-' . $BASE_LEN); # see USE_MUL 80 $MAX_VAL = $BASE-1; 81 82 # ($caught & 1) != 0 => cannot use MUL 83 # ($caught & 2) != 0 => cannot use DIV 84 if ($caught == 2) # 2 85 { 86 # must USE_MUL since we cannot use DIV 87 *_mul = \&_mul_use_mul; 88 *_div = \&_div_use_mul; 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, $BASE, $AND_BITS, $XOR_BITS, $OR_BITS, $BASE_LEN, $MAX_VAL); 98} 99 100sub _new { 101 # Given a string representing an integer, returns a reference to an array 102 # of integers, where each integer represents a chunk of the original input 103 # integer. 104 105 my ($class, $str) = @_; 106 #unless ($str =~ /^([1-9]\d*|0)\z/) { 107 # require Carp; 108 # Carp::croak("Invalid input string '$str'"); 109 #} 110 111 my $input_len = length($str) - 1; 112 113 # Shortcut for small numbers. 114 return bless [ $str ], $class if $input_len < $BASE_LEN; 115 116 my $format = "a" . (($input_len % $BASE_LEN) + 1); 117 $format .= $] < 5.008 ? "a$BASE_LEN" x int($input_len / $BASE_LEN) 118 : "(a$BASE_LEN)*"; 119 120 my $self = [ reverse(map { 0 + $_ } unpack($format, $str)) ]; 121 return bless $self, $class; 122} 123 124BEGIN { 125 # from Daniel Pfeiffer: determine largest group of digits that is precisely 126 # multipliable with itself plus carry 127 # Test now changed to expect the proper pattern, not a result off by 1 or 2 128 my ($e, $num) = 3; # lowest value we will use is 3+1-1 = 3 129 do { 130 $num = '9' x ++$e; 131 $num *= $num + 1; 132 } while $num =~ /9{$e}0{$e}/; # must be a certain pattern 133 $e--; # last test failed, so retract one step 134 # the limits below brush the problems with the test above under the rug: 135 # the test should be able to find the proper $e automatically 136 $e = 5 if $^O =~ /^uts/; # UTS get's some special treatment 137 $e = 5 if $^O =~ /^unicos/; # unicos is also problematic (6 seems to work 138 # there, but we play safe) 139 140 my $int = 0; 141 if ($e > 7) { 142 use integer; 143 my $e1 = 7; 144 $num = 7; 145 do { 146 $num = ('9' x ++$e1) + 0; 147 $num *= $num + 1; 148 } while ("$num" =~ /9{$e1}0{$e1}/); # must be a certain pattern 149 $e1--; # last test failed, so retract one step 150 if ($e1 > 7) { 151 $int = 1; 152 $e = $e1; 153 } 154 } 155 156 __PACKAGE__ -> _base_len($e, $int); # set and store 157 158 use integer; 159 # find out how many bits _and, _or and _xor can take (old default = 16) 160 # I don't think anybody has yet 128 bit scalars, so let's play safe. 161 local $^W = 0; # don't warn about 'nonportable number' 162 $AND_BITS = 15; 163 $XOR_BITS = 15; 164 $OR_BITS = 15; 165 166 # find max bits, we will not go higher than numberofbits that fit into $BASE 167 # to make _and etc simpler (and faster for smaller, slower for large numbers) 168 my $max = 16; 169 while (2 ** $max < $BASE) { 170 $max++; 171 } 172 { 173 no integer; 174 $max = 16 if $] < 5.006; # older Perls might not take >16 too well 175 } 176 my ($x, $y, $z); 177 178 do { 179 $AND_BITS++; 180 $x = CORE::oct('0b' . '1' x $AND_BITS); 181 $y = $x & $x; 182 $z = (2 ** $AND_BITS) - 1; 183 } while ($AND_BITS < $max && $x == $z && $y == $x); 184 $AND_BITS --; # retreat one step 185 186 do { 187 $XOR_BITS++; 188 $x = CORE::oct('0b' . '1' x $XOR_BITS); 189 $y = $x ^ 0; 190 $z = (2 ** $XOR_BITS) - 1; 191 } while ($XOR_BITS < $max && $x == $z && $y == $x); 192 $XOR_BITS --; # retreat one step 193 194 do { 195 $OR_BITS++; 196 $x = CORE::oct('0b' . '1' x $OR_BITS); 197 $y = $x | $x; 198 $z = (2 ** $OR_BITS) - 1; 199 } while ($OR_BITS < $max && $x == $z && $y == $x); 200 $OR_BITS--; # retreat one step 201 202 $AND_MASK = __PACKAGE__->_new(( 2 ** $AND_BITS )); 203 $XOR_MASK = __PACKAGE__->_new(( 2 ** $XOR_BITS )); 204 $OR_MASK = __PACKAGE__->_new(( 2 ** $OR_BITS )); 205 206 # We can compute the approximate length no faster than the real length: 207 *_alen = \&_len; 208} 209 210############################################################################### 211 212sub _zero { 213 # create a zero 214 my $class = shift; 215 return bless [ 0 ], $class; 216} 217 218sub _one { 219 # create a one 220 my $class = shift; 221 return bless [ 1 ], $class; 222} 223 224sub _two { 225 # create a two 226 my $class = shift; 227 return bless [ 2 ], $class; 228} 229 230sub _ten { 231 # create a 10 232 my $class = shift; 233 bless [ 10 ], $class; 234} 235 236sub _1ex { 237 # create a 1Ex 238 my $class = shift; 239 240 my $rem = $_[0] % $BASE_LEN; # remainder 241 my $parts = $_[0] / $BASE_LEN; # parts 242 243 # 000000, 000000, 100 244 bless [ (0) x $parts, '1' . ('0' x $rem) ], $class; 245} 246 247sub _copy { 248 # make a true copy 249 my $class = shift; 250 return bless [ @{ $_[0] } ], $class; 251} 252 253# catch and throw away 254sub import { } 255 256############################################################################## 257# convert back to string and number 258 259sub _str { 260 # Convert number from internal base 1eN format to string format. Internal 261 # format is always normalized, i.e., no leading zeros. 262 263 my $ary = $_[1]; 264 my $idx = $#$ary; # index of last element 265 266 if ($idx < 0) { # should not happen 267 require Carp; 268 Carp::croak("$_[1] has no elements"); 269 } 270 271 # Handle first one differently, since it should not have any leading zeros. 272 my $ret = int($ary->[$idx]); 273 if ($idx > 0) { 274 # Interestingly, the pre-padd method uses more time. 275 # The old grep variant takes longer (14 vs. 10 sec). 276 my $z = '0' x ($BASE_LEN - 1); 277 while (--$idx >= 0) { 278 $ret .= substr($z . $ary->[$idx], -$BASE_LEN); 279 } 280 } 281 $ret; 282} 283 284sub _num { 285 # Make a Perl scalar number (int/float) from a BigInt object. 286 my $x = $_[1]; 287 288 return $x->[0] if @$x == 1; # below $BASE 289 290 # Start with the most significant element and work towards the least 291 # significant element. Avoid multiplying "inf" (which happens if the number 292 # overflows) with "0" (if there are zero elements in $x) since this gives 293 # "nan" which propagates to the output. 294 295 my $num = 0; 296 for (my $i = $#$x ; $i >= 0 ; --$i) { 297 $num *= $BASE; 298 $num += $x -> [$i]; 299 } 300 return $num; 301} 302 303############################################################################## 304# actual math code 305 306sub _add { 307 # (ref to int_num_array, ref to int_num_array) 308 # 309 # Routine to add two base 1eX numbers stolen from Knuth Vol 2 Algorithm A 310 # pg 231. There are separate routines to add and sub as per Knuth pg 233. 311 # This routine modifies array x, but not y. 312 313 my ($c, $x, $y) = @_; 314 315 # $x + 0 => $x 316 317 return $x if @$y == 1 && $y->[0] == 0; 318 319 # 0 + $y => $y->copy 320 321 if (@$x == 1 && $x->[0] == 0) { 322 @$x = @$y; 323 return $x; 324 } 325 326 # For each in Y, add Y to X and carry. If after that, something is left in 327 # X, foreach in X add carry to X and then return X, carry. Trades one 328 # "$j++" for having to shift arrays. 329 my $i; 330 my $car = 0; 331 my $j = 0; 332 for $i (@$y) { 333 $x->[$j] -= $BASE if $car = (($x->[$j] += $i + $car) >= $BASE) ? 1 : 0; 334 $j++; 335 } 336 while ($car != 0) { 337 $x->[$j] -= $BASE if $car = (($x->[$j] += $car) >= $BASE) ? 1 : 0; 338 $j++; 339 } 340 $x; 341} 342 343sub _inc { 344 # (ref to int_num_array, ref to int_num_array) 345 # Add 1 to $x, modify $x in place 346 my ($c, $x) = @_; 347 348 for my $i (@$x) { 349 return $x if ($i += 1) < $BASE; # early out 350 $i = 0; # overflow, next 351 } 352 push @$x, 1 if $x->[-1] == 0; # last overflowed, so extend 353 $x; 354} 355 356sub _dec { 357 # (ref to int_num_array, ref to int_num_array) 358 # Sub 1 from $x, modify $x in place 359 my ($c, $x) = @_; 360 361 my $MAX = $BASE - 1; # since MAX_VAL based on BASE 362 for my $i (@$x) { 363 last if ($i -= 1) >= 0; # early out 364 $i = $MAX; # underflow, next 365 } 366 pop @$x if $x->[-1] == 0 && @$x > 1; # last underflowed (but leave 0) 367 $x; 368} 369 370sub _sub { 371 # (ref to int_num_array, ref to int_num_array, swap) 372 # 373 # Subtract base 1eX numbers -- stolen from Knuth Vol 2 pg 232, $x > $y 374 # subtract Y from X by modifying x in place 375 my ($c, $sx, $sy, $s) = @_; 376 377 my $car = 0; 378 my $i; 379 my $j = 0; 380 if (!$s) { 381 for $i (@$sx) { 382 last unless defined $sy->[$j] || $car; 383 $i += $BASE if $car = (($i -= ($sy->[$j] || 0) + $car) < 0); 384 $j++; 385 } 386 # might leave leading zeros, so fix that 387 return __strip_zeros($sx); 388 } 389 for $i (@$sx) { 390 # We can't do an early out if $x < $y, since we need to copy the high 391 # chunks from $y. Found by Bob Mathews. 392 #last unless defined $sy->[$j] || $car; 393 $sy->[$j] += $BASE 394 if $car = ($sy->[$j] = $i - ($sy->[$j] || 0) - $car) < 0; 395 $j++; 396 } 397 # might leave leading zeros, so fix that 398 __strip_zeros($sy); 399} 400 401sub _mul_use_mul { 402 # (ref to int_num_array, ref to int_num_array) 403 # multiply two numbers in internal representation 404 # modifies first arg, second need not be different from first 405 my ($c, $xv, $yv) = @_; 406 407 if (@$yv == 1) { 408 # shortcut for two very short numbers (improved by Nathan Zook) 409 # works also if xv and yv are the same reference, and handles also $x == 0 410 if (@$xv == 1) { 411 if (($xv->[0] *= $yv->[0]) >= $BASE) { 412 $xv->[0] = $xv->[0] - ($xv->[1] = int($xv->[0] * $RBASE)) * $BASE; 413 } 414 ; 415 return $xv; 416 } 417 # $x * 0 => 0 418 if ($yv->[0] == 0) { 419 @$xv = (0); 420 return $xv; 421 } 422 # multiply a large number a by a single element one, so speed up 423 my $y = $yv->[0]; 424 my $car = 0; 425 foreach my $i (@$xv) { 426 $i = $i * $y + $car; 427 $car = int($i * $RBASE); 428 $i -= $car * $BASE; 429 } 430 push @$xv, $car if $car != 0; 431 return $xv; 432 } 433 # shortcut for result $x == 0 => result = 0 434 return $xv if @$xv == 1 && $xv->[0] == 0; 435 436 # since multiplying $x with $x fails, make copy in this case 437 $yv = [ @$xv ] if $xv == $yv; # same references? 438 439 my @prod = (); 440 my ($prod, $car, $cty, $xi, $yi); 441 442 for $xi (@$xv) { 443 $car = 0; 444 $cty = 0; 445 446 # slow variant 447 # for $yi (@$yv) 448 # { 449 # $prod = $xi * $yi + ($prod[$cty] || 0) + $car; 450 # $prod[$cty++] = 451 # $prod - ($car = int($prod * RBASE)) * $BASE; # see USE_MUL 452 # } 453 # $prod[$cty] += $car if $car; # need really to check for 0? 454 # $xi = shift @prod; 455 456 # faster variant 457 # looping through this if $xi == 0 is silly - so optimize it away! 458 $xi = (shift @prod || 0), next if $xi == 0; 459 for $yi (@$yv) { 460 $prod = $xi * $yi + ($prod[$cty] || 0) + $car; 461 ## this is actually a tad slower 462 ## $prod = $prod[$cty]; $prod += ($car + $xi * $yi); # no ||0 here 463 $prod[$cty++] = 464 $prod - ($car = int($prod * $RBASE)) * $BASE; # see USE_MUL 465 } 466 $prod[$cty] += $car if $car; # need really to check for 0? 467 $xi = shift @prod || 0; # || 0 makes v5.005_3 happy 468 } 469 push @$xv, @prod; 470 # can't have leading zeros 471 # __strip_zeros($xv); 472 $xv; 473} 474 475sub _mul_use_div_64 { 476 # (ref to int_num_array, ref to int_num_array) 477 # multiply two numbers in internal representation 478 # modifies first arg, second need not be different from first 479 # works for 64 bit integer with "use integer" 480 my ($c, $xv, $yv) = @_; 481 482 use integer; 483 if (@$yv == 1) { 484 # shortcut for two small numbers, also handles $x == 0 485 if (@$xv == 1) { 486 # shortcut for two very short numbers (improved by Nathan Zook) 487 # works also if xv and yv are the same reference, and handles also $x == 0 488 if (($xv->[0] *= $yv->[0]) >= $BASE) { 489 $xv->[0] = 490 $xv->[0] - ($xv->[1] = $xv->[0] / $BASE) * $BASE; 491 } 492 return $xv; 493 } 494 # $x * 0 => 0 495 if ($yv->[0] == 0) { 496 @$xv = (0); 497 return $xv; 498 } 499 # multiply a large number a by a single element one, so speed up 500 my $y = $yv->[0]; 501 my $car = 0; 502 foreach my $i (@$xv) { 503 #$i = $i * $y + $car; $car = $i / $BASE; $i -= $car * $BASE; 504 $i = $i * $y + $car; 505 $i -= ($car = $i / $BASE) * $BASE; 506 } 507 push @$xv, $car if $car != 0; 508 return $xv; 509 } 510 # shortcut for result $x == 0 => result = 0 511 return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) ); 512 513 # since multiplying $x with $x fails, make copy in this case 514 $yv = $c->_copy($xv) if $xv == $yv; # same references? 515 516 my @prod = (); 517 my ($prod, $car, $cty, $xi, $yi); 518 for $xi (@$xv) { 519 $car = 0; 520 $cty = 0; 521 # looping through this if $xi == 0 is silly - so optimize it away! 522 $xi = (shift @prod || 0), next if $xi == 0; 523 for $yi (@$yv) { 524 $prod = $xi * $yi + ($prod[$cty] || 0) + $car; 525 $prod[$cty++] = $prod - ($car = $prod / $BASE) * $BASE; 526 } 527 $prod[$cty] += $car if $car; # need really to check for 0? 528 $xi = shift @prod || 0; # || 0 makes v5.005_3 happy 529 } 530 push @$xv, @prod; 531 $xv; 532} 533 534sub _mul_use_div { 535 # (ref to int_num_array, ref to int_num_array) 536 # multiply two numbers in internal representation 537 # modifies first arg, second need not be different from first 538 my ($c, $xv, $yv) = @_; 539 540 if (@$yv == 1) { 541 # shortcut for two small numbers, also handles $x == 0 542 if (@$xv == 1) { 543 # shortcut for two very short numbers (improved by Nathan Zook) 544 # works also if xv and yv are the same reference, and handles also $x == 0 545 if (($xv->[0] *= $yv->[0]) >= $BASE) { 546 $xv->[0] = 547 $xv->[0] - ($xv->[1] = int($xv->[0] / $BASE)) * $BASE; 548 } 549 ; 550 return $xv; 551 } 552 # $x * 0 => 0 553 if ($yv->[0] == 0) { 554 @$xv = (0); 555 return $xv; 556 } 557 # multiply a large number a by a single element one, so speed up 558 my $y = $yv->[0]; 559 my $car = 0; 560 foreach my $i (@$xv) { 561 $i = $i * $y + $car; 562 $car = int($i / $BASE); 563 $i -= $car * $BASE; 564 # This (together with use integer;) does not work on 32-bit Perls 565 #$i = $i * $y + $car; $i -= ($car = $i / $BASE) * $BASE; 566 } 567 push @$xv, $car if $car != 0; 568 return $xv; 569 } 570 # shortcut for result $x == 0 => result = 0 571 return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) ); 572 573 # since multiplying $x with $x fails, make copy in this case 574 $yv = $c->_copy($xv) if $xv == $yv; # same references? 575 576 my @prod = (); 577 my ($prod, $car, $cty, $xi, $yi); 578 for $xi (@$xv) { 579 $car = 0; 580 $cty = 0; 581 # looping through this if $xi == 0 is silly - so optimize it away! 582 $xi = (shift @prod || 0), next if $xi == 0; 583 for $yi (@$yv) { 584 $prod = $xi * $yi + ($prod[$cty] || 0) + $car; 585 $prod[$cty++] = $prod - ($car = int($prod / $BASE)) * $BASE; 586 } 587 $prod[$cty] += $car if $car; # need really to check for 0? 588 $xi = shift @prod || 0; # || 0 makes v5.005_3 happy 589 } 590 push @$xv, @prod; 591 # can't have leading zeros 592 # __strip_zeros($xv); 593 $xv; 594} 595 596sub _div_use_mul { 597 # ref to array, ref to array, modify first array and return remainder if 598 # in list context 599 600 # see comments in _div_use_div() for more explanations 601 602 my ($c, $x, $yorg) = @_; 603 604 # the general div algorithm here is about O(N*N) and thus quite slow, so 605 # we first check for some special cases and use shortcuts to handle them. 606 607 # This works, because we store the numbers in a chunked format where each 608 # element contains 5..7 digits (depending on system). 609 610 # if both numbers have only one element: 611 if (@$x == 1 && @$yorg == 1) { 612 # shortcut, $yorg and $x are two small numbers 613 if (wantarray) { 614 my $rem = [ $x->[0] % $yorg->[0] ]; 615 bless $rem, $c; 616 $x->[0] = int($x->[0] / $yorg->[0]); 617 return ($x, $rem); 618 } else { 619 $x->[0] = int($x->[0] / $yorg->[0]); 620 return $x; 621 } 622 } 623 624 # if x has more than one, but y has only one element: 625 if (@$yorg == 1) { 626 my $rem; 627 $rem = $c->_mod($c->_copy($x), $yorg) if wantarray; 628 629 # shortcut, $y is < $BASE 630 my $j = @$x; 631 my $r = 0; 632 my $y = $yorg->[0]; 633 my $b; 634 while ($j-- > 0) { 635 $b = $r * $BASE + $x->[$j]; 636 $x->[$j] = int($b/$y); 637 $r = $b % $y; 638 } 639 pop @$x if @$x > 1 && $x->[-1] == 0; # splice up a leading zero 640 return ($x, $rem) if wantarray; 641 return $x; 642 } 643 644 # now x and y have more than one element 645 646 # check whether y has more elements than x, if yet, the result will be 0 647 if (@$yorg > @$x) { 648 my $rem; 649 $rem = $c->_copy($x) if wantarray; # make copy 650 @$x = 0; # set to 0 651 return ($x, $rem) if wantarray; # including remainder? 652 return $x; # only x, which is [0] now 653 } 654 # check whether the numbers have the same number of elements, in that case 655 # the result will fit into one element and can be computed efficiently 656 if (@$yorg == @$x) { 657 658 # if $yorg has more digits than $x (it's leading element is longer than 659 # the one from $x), the result will also be 0: 660 if (length(int($yorg->[-1])) > length(int($x->[-1]))) { 661 my $rem = $c->_copy($x) if wantarray; # make copy 662 @$x = 0; # set to 0 663 return ($x, $rem) if wantarray; # including remainder? 664 return $x; 665 } 666 # now calculate $x / $yorg 667 if (length(int($yorg->[-1])) == length(int($x->[-1]))) { 668 # same length, so make full compare 669 670 my $a = 0; 671 my $j = @$x - 1; 672 # manual way (abort if unequal, good for early ne) 673 while ($j >= 0) { 674 last if ($a = $x->[$j] - $yorg->[$j]); 675 $j--; 676 } 677 # $a contains the result of the compare between X and Y 678 # a < 0: x < y, a == 0: x == y, a > 0: x > y 679 if ($a <= 0) { 680 # a = 0 => x == y => rem 0 681 # a < 0 => x < y => rem = x 682 my $rem = $a == 0 ? $c->_zero() : $c->_copy($x); 683 @$x = 0; # if $a < 0 684 $x->[0] = 1 if $a == 0; # $x == $y 685 return ($x, $rem) if wantarray; 686 return $x; 687 } 688 # $x >= $y, so proceed normally 689 } 690 } 691 692 # all other cases: 693 694 my $y = $c->_copy($yorg); # always make copy to preserve 695 696 my ($car, $bar, $prd, $dd, $xi, $yi, @q, $v2, $v1, @d, $tmp, $q, $u2, $u1, $u0); 697 698 $car = $bar = $prd = 0; 699 if (($dd = int($BASE / ($y->[-1] + 1))) != 1) { 700 for $xi (@$x) { 701 $xi = $xi * $dd + $car; 702 $xi -= ($car = int($xi * $RBASE)) * $BASE; # see USE_MUL 703 } 704 push(@$x, $car); 705 $car = 0; 706 for $yi (@$y) { 707 $yi = $yi * $dd + $car; 708 $yi -= ($car = int($yi * $RBASE)) * $BASE; # see USE_MUL 709 } 710 } else { 711 push(@$x, 0); 712 } 713 @q = (); 714 ($v2, $v1) = @$y[-2, -1]; 715 $v2 = 0 unless $v2; 716 while ($#$x > $#$y) { 717 ($u2, $u1, $u0) = @$x[-3 .. -1]; 718 $u2 = 0 unless $u2; 719 #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n" 720 # if $v1 == 0; 721 $q = (($u0 == $v1) ? $MAX_VAL : int(($u0 * $BASE + $u1) / $v1)); 722 --$q while ($v2 * $q > ($u0 * $BASE + $u1 - $q * $v1) * $BASE + $u2); 723 if ($q) { 724 ($car, $bar) = (0, 0); 725 for ($yi = 0, $xi = $#$x - $#$y-1; $yi <= $#$y; ++$yi, ++$xi) { 726 $prd = $q * $y->[$yi] + $car; 727 $prd -= ($car = int($prd * $RBASE)) * $BASE; # see USE_MUL 728 $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0)); 729 } 730 if ($x->[-1] < $car + $bar) { 731 $car = 0; 732 --$q; 733 for ($yi = 0, $xi = $#$x - $#$y-1; $yi <= $#$y; ++$yi, ++$xi) { 734 $x->[$xi] -= $BASE 735 if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE)); 736 } 737 } 738 } 739 pop(@$x); 740 unshift(@q, $q); 741 } 742 if (wantarray) { 743 my $d = bless [], $c; 744 if ($dd != 1) { 745 $car = 0; 746 for $xi (reverse @$x) { 747 $prd = $car * $BASE + $xi; 748 $car = $prd - ($tmp = int($prd / $dd)) * $dd; # see USE_MUL 749 unshift(@$d, $tmp); 750 } 751 } else { 752 @$d = @$x; 753 } 754 @$x = @q; 755 __strip_zeros($x); 756 __strip_zeros($d); 757 return ($x, $d); 758 } 759 @$x = @q; 760 __strip_zeros($x); 761 $x; 762} 763 764sub _div_use_div_64 { 765 # ref to array, ref to array, modify first array and return remainder if 766 # in list context 767 # This version works on 64 bit integers 768 my ($c, $x, $yorg) = @_; 769 770 use integer; 771 # the general div algorithm here is about O(N*N) and thus quite slow, so 772 # we first check for some special cases and use shortcuts to handle them. 773 774 # This works, because we store the numbers in a chunked format where each 775 # element contains 5..7 digits (depending on system). 776 777 # if both numbers have only one element: 778 if (@$x == 1 && @$yorg == 1) { 779 # shortcut, $yorg and $x are two small numbers 780 if (wantarray) { 781 my $rem = [ $x->[0] % $yorg->[0] ]; 782 bless $rem, $c; 783 $x->[0] = int($x->[0] / $yorg->[0]); 784 return ($x, $rem); 785 } else { 786 $x->[0] = int($x->[0] / $yorg->[0]); 787 return $x; 788 } 789 } 790 # if x has more than one, but y has only one element: 791 if (@$yorg == 1) { 792 my $rem; 793 $rem = $c->_mod($c->_copy($x), $yorg) if wantarray; 794 795 # shortcut, $y is < $BASE 796 my $j = @$x; 797 my $r = 0; 798 my $y = $yorg->[0]; 799 my $b; 800 while ($j-- > 0) { 801 $b = $r * $BASE + $x->[$j]; 802 $x->[$j] = int($b/$y); 803 $r = $b % $y; 804 } 805 pop @$x if @$x > 1 && $x->[-1] == 0; # splice up a leading zero 806 return ($x, $rem) if wantarray; 807 return $x; 808 } 809 # now x and y have more than one element 810 811 # check whether y has more elements than x, if yet, the result will be 0 812 if (@$yorg > @$x) { 813 my $rem; 814 $rem = $c->_copy($x) if wantarray; # make copy 815 @$x = 0; # set to 0 816 return ($x, $rem) if wantarray; # including remainder? 817 return $x; # only x, which is [0] now 818 } 819 # check whether the numbers have the same number of elements, in that case 820 # the result will fit into one element and can be computed efficiently 821 if (@$yorg == @$x) { 822 my $rem; 823 # if $yorg has more digits than $x (it's leading element is longer than 824 # the one from $x), the result will also be 0: 825 if (length(int($yorg->[-1])) > length(int($x->[-1]))) { 826 $rem = $c->_copy($x) if wantarray; # make copy 827 @$x = 0; # set to 0 828 return ($x, $rem) if wantarray; # including remainder? 829 return $x; 830 } 831 # now calculate $x / $yorg 832 833 if (length(int($yorg->[-1])) == length(int($x->[-1]))) { 834 # same length, so make full compare 835 836 my $a = 0; 837 my $j = @$x - 1; 838 # manual way (abort if unequal, good for early ne) 839 while ($j >= 0) { 840 last if ($a = $x->[$j] - $yorg->[$j]); 841 $j--; 842 } 843 # $a contains the result of the compare between X and Y 844 # a < 0: x < y, a == 0: x == y, a > 0: x > y 845 if ($a <= 0) { 846 $rem = $c->_zero(); # a = 0 => x == y => rem 0 847 $rem = $c->_copy($x) if $a != 0; # a < 0 => x < y => rem = x 848 @$x = 0; # if $a < 0 849 $x->[0] = 1 if $a == 0; # $x == $y 850 return ($x, $rem) if wantarray; # including remainder? 851 return $x; 852 } 853 # $x >= $y, so proceed normally 854 } 855 } 856 857 # all other cases: 858 859 my $y = $c->_copy($yorg); # always make copy to preserve 860 861 my ($car, $bar, $prd, $dd, $xi, $yi, @q, $v2, $v1, @d, $tmp, $q, $u2, $u1, $u0); 862 863 $car = $bar = $prd = 0; 864 if (($dd = int($BASE / ($y->[-1] + 1))) != 1) { 865 for $xi (@$x) { 866 $xi = $xi * $dd + $car; 867 $xi -= ($car = int($xi / $BASE)) * $BASE; 868 } 869 push(@$x, $car); 870 $car = 0; 871 for $yi (@$y) { 872 $yi = $yi * $dd + $car; 873 $yi -= ($car = int($yi / $BASE)) * $BASE; 874 } 875 } else { 876 push(@$x, 0); 877 } 878 879 # @q will accumulate the final result, $q contains the current computed 880 # part of the final result 881 882 @q = (); 883 ($v2, $v1) = @$y[-2, -1]; 884 $v2 = 0 unless $v2; 885 while ($#$x > $#$y) { 886 ($u2, $u1, $u0) = @$x[-3..-1]; 887 $u2 = 0 unless $u2; 888 #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n" 889 # if $v1 == 0; 890 $q = (($u0 == $v1) ? $MAX_VAL : int(($u0 * $BASE + $u1) / $v1)); 891 --$q while ($v2 * $q > ($u0 * $BASE +$ u1- $q*$v1) * $BASE + $u2); 892 if ($q) { 893 ($car, $bar) = (0, 0); 894 for ($yi = 0, $xi = $#$x - $#$y - 1; $yi <= $#$y; ++$yi, ++$xi) { 895 $prd = $q * $y->[$yi] + $car; 896 $prd -= ($car = int($prd / $BASE)) * $BASE; 897 $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0)); 898 } 899 if ($x->[-1] < $car + $bar) { 900 $car = 0; 901 --$q; 902 for ($yi = 0, $xi = $#$x - $#$y - 1; $yi <= $#$y; ++$yi, ++$xi) { 903 $x->[$xi] -= $BASE 904 if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE)); 905 } 906 } 907 } 908 pop(@$x); 909 unshift(@q, $q); 910 } 911 if (wantarray) { 912 my $d = bless [], $c; 913 if ($dd != 1) { 914 $car = 0; 915 for $xi (reverse @$x) { 916 $prd = $car * $BASE + $xi; 917 $car = $prd - ($tmp = int($prd / $dd)) * $dd; 918 unshift(@$d, $tmp); 919 } 920 } else { 921 @$d = @$x; 922 } 923 @$x = @q; 924 __strip_zeros($x); 925 __strip_zeros($d); 926 return ($x, $d); 927 } 928 @$x = @q; 929 __strip_zeros($x); 930 $x; 931} 932 933sub _div_use_div { 934 # ref to array, ref to array, modify first array and return remainder if 935 # in list context 936 my ($c, $x, $yorg) = @_; 937 938 # the general div algorithm here is about O(N*N) and thus quite slow, so 939 # we first check for some special cases and use shortcuts to handle them. 940 941 # This works, because we store the numbers in a chunked format where each 942 # element contains 5..7 digits (depending on system). 943 944 # if both numbers have only one element: 945 if (@$x == 1 && @$yorg == 1) { 946 # shortcut, $yorg and $x are two small numbers 947 if (wantarray) { 948 my $rem = [ $x->[0] % $yorg->[0] ]; 949 bless $rem, $c; 950 $x->[0] = int($x->[0] / $yorg->[0]); 951 return ($x, $rem); 952 } else { 953 $x->[0] = int($x->[0] / $yorg->[0]); 954 return $x; 955 } 956 } 957 # if x has more than one, but y has only one element: 958 if (@$yorg == 1) { 959 my $rem; 960 $rem = $c->_mod($c->_copy($x), $yorg) if wantarray; 961 962 # shortcut, $y is < $BASE 963 my $j = @$x; 964 my $r = 0; 965 my $y = $yorg->[0]; 966 my $b; 967 while ($j-- > 0) { 968 $b = $r * $BASE + $x->[$j]; 969 $x->[$j] = int($b/$y); 970 $r = $b % $y; 971 } 972 pop @$x if @$x > 1 && $x->[-1] == 0; # splice up a leading zero 973 return ($x, $rem) if wantarray; 974 return $x; 975 } 976 # now x and y have more than one element 977 978 # check whether y has more elements than x, if yet, the result will be 0 979 if (@$yorg > @$x) { 980 my $rem; 981 $rem = $c->_copy($x) if wantarray; # make copy 982 @$x = 0; # set to 0 983 return ($x, $rem) if wantarray; # including remainder? 984 return $x; # only x, which is [0] now 985 } 986 # check whether the numbers have the same number of elements, in that case 987 # the result will fit into one element and can be computed efficiently 988 if (@$yorg == @$x) { 989 my $rem; 990 # if $yorg has more digits than $x (it's leading element is longer than 991 # the one from $x), the result will also be 0: 992 if (length(int($yorg->[-1])) > length(int($x->[-1]))) { 993 $rem = $c->_copy($x) if wantarray; # make copy 994 @$x = 0; # set to 0 995 return ($x, $rem) if wantarray; # including remainder? 996 return $x; 997 } 998 # now calculate $x / $yorg 999 1000 if (length(int($yorg->[-1])) == length(int($x->[-1]))) { 1001 # same length, so make full compare 1002 1003 my $a = 0; 1004 my $j = @$x - 1; 1005 # manual way (abort if unequal, good for early ne) 1006 while ($j >= 0) { 1007 last if ($a = $x->[$j] - $yorg->[$j]); 1008 $j--; 1009 } 1010 # $a contains the result of the compare between X and Y 1011 # a < 0: x < y, a == 0: x == y, a > 0: x > y 1012 if ($a <= 0) { 1013 $rem = $c->_zero(); # a = 0 => x == y => rem 0 1014 $rem = $c->_copy($x) if $a != 0; # a < 0 => x < y => rem = x 1015 @$x = 0; 1016 $x->[0] = 0; # if $a < 0 1017 $x->[0] = 1 if $a == 0; # $x == $y 1018 return ($x, $rem) if wantarray; # including remainder? 1019 return $x; 1020 } 1021 # $x >= $y, so proceed normally 1022 1023 } 1024 } 1025 1026 # all other cases: 1027 1028 my $y = $c->_copy($yorg); # always make copy to preserve 1029 1030 my ($car, $bar, $prd, $dd, $xi, $yi, @q, $v2, $v1, @d, $tmp, $q, $u2, $u1, $u0); 1031 1032 $car = $bar = $prd = 0; 1033 if (($dd = int($BASE / ($y->[-1] + 1))) != 1) { 1034 for $xi (@$x) { 1035 $xi = $xi * $dd + $car; 1036 $xi -= ($car = int($xi / $BASE)) * $BASE; 1037 } 1038 push(@$x, $car); 1039 $car = 0; 1040 for $yi (@$y) { 1041 $yi = $yi * $dd + $car; 1042 $yi -= ($car = int($yi / $BASE)) * $BASE; 1043 } 1044 } else { 1045 push(@$x, 0); 1046 } 1047 1048 # @q will accumulate the final result, $q contains the current computed 1049 # part of the final result 1050 1051 @q = (); 1052 ($v2, $v1) = @$y[-2, -1]; 1053 $v2 = 0 unless $v2; 1054 while ($#$x > $#$y) { 1055 ($u2, $u1, $u0) = @$x[-3..-1]; 1056 $u2 = 0 unless $u2; 1057 #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n" 1058 # if $v1 == 0; 1059 $q = (($u0 == $v1) ? $MAX_VAL : int(($u0 * $BASE + $u1) / $v1)); 1060 --$q while ($v2 * $q > ($u0 * $BASE + $u1 - $q * $v1) * $BASE + $u2); 1061 if ($q) { 1062 ($car, $bar) = (0, 0); 1063 for ($yi = 0, $xi = $#$x - $#$y - 1; $yi <= $#$y; ++$yi, ++$xi) { 1064 $prd = $q * $y->[$yi] + $car; 1065 $prd -= ($car = int($prd / $BASE)) * $BASE; 1066 $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0)); 1067 } 1068 if ($x->[-1] < $car + $bar) { 1069 $car = 0; 1070 --$q; 1071 for ($yi = 0, $xi = $#$x - $#$y - 1; $yi <= $#$y; ++$yi, ++$xi) { 1072 $x->[$xi] -= $BASE 1073 if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE)); 1074 } 1075 } 1076 } 1077 pop(@$x); 1078 unshift(@q, $q); 1079 } 1080 if (wantarray) { 1081 my $d = bless [], $c; 1082 if ($dd != 1) { 1083 $car = 0; 1084 for $xi (reverse @$x) { 1085 $prd = $car * $BASE + $xi; 1086 $car = $prd - ($tmp = int($prd / $dd)) * $dd; 1087 unshift(@$d, $tmp); 1088 } 1089 } else { 1090 @$d = @$x; 1091 } 1092 @$x = @q; 1093 __strip_zeros($x); 1094 __strip_zeros($d); 1095 return ($x, $d); 1096 } 1097 @$x = @q; 1098 __strip_zeros($x); 1099 $x; 1100} 1101 1102############################################################################## 1103# testing 1104 1105sub _acmp { 1106 # Internal absolute post-normalized compare (ignore signs) 1107 # ref to array, ref to array, return <0, 0, >0 1108 # Arrays must have at least one entry; this is not checked for. 1109 my ($c, $cx, $cy) = @_; 1110 1111 # shortcut for short numbers 1112 return (($cx->[0] <=> $cy->[0]) <=> 0) 1113 if @$cx == 1 && @$cy == 1; 1114 1115 # fast comp based on number of array elements (aka pseudo-length) 1116 my $lxy = (@$cx - @$cy) 1117 # or length of first element if same number of elements (aka difference 0) 1118 || 1119 # need int() here because sometimes the last element is '00018' vs '18' 1120 (length(int($cx->[-1])) - length(int($cy->[-1]))); 1121 1122 return -1 if $lxy < 0; # already differs, ret 1123 return 1 if $lxy > 0; # ditto 1124 1125 # manual way (abort if unequal, good for early ne) 1126 my $a; 1127 my $j = @$cx; 1128 while (--$j >= 0) { 1129 last if $a = $cx->[$j] - $cy->[$j]; 1130 } 1131 $a <=> 0; 1132} 1133 1134sub _len { 1135 # compute number of digits in base 10 1136 1137 # int() because add/sub sometimes leaves strings (like '00005') instead of 1138 # '5' in this place, thus causing length() to report wrong length 1139 my $cx = $_[1]; 1140 1141 (@$cx - 1) * $BASE_LEN + length(int($cx->[-1])); 1142} 1143 1144sub _digit { 1145 # Return the nth digit. Zero is rightmost, so _digit(123, 0) gives 3. 1146 # Negative values count from the left, so _digit(123, -1) gives 1. 1147 my ($c, $x, $n) = @_; 1148 1149 my $len = _len('', $x); 1150 1151 $n += $len if $n < 0; # -1 last, -2 second-to-last 1152 1153 # Math::BigInt::Calc returns 0 if N is out of range, but this is not done 1154 # by the other backend libraries. 1155 1156 return "0" if $n < 0 || $n >= $len; # return 0 for digits out of range 1157 1158 my $elem = int($n / $BASE_LEN); # index of array element 1159 my $digit = $n % $BASE_LEN; # index of digit within the element 1160 substr("0" x $BASE_LEN . "$x->[$elem]", -1 - $digit, 1); 1161} 1162 1163sub _zeros { 1164 # Return number of trailing zeros in decimal. 1165 # Check each array element for having 0 at end as long as elem == 0 1166 # Upon finding a elem != 0, stop. 1167 1168 my $x = $_[1]; 1169 1170 return 0 if @$x == 1 && $x->[0] == 0; 1171 1172 my $zeros = 0; 1173 foreach my $elem (@$x) { 1174 if ($elem != 0) { 1175 $elem =~ /[^0](0*)\z/; 1176 $zeros += length($1); # count trailing zeros 1177 last; # early out 1178 } 1179 $zeros += $BASE_LEN; 1180 } 1181 $zeros; 1182} 1183 1184############################################################################## 1185# _is_* routines 1186 1187sub _is_zero { 1188 # return true if arg is zero 1189 @{$_[1]} == 1 && $_[1]->[0] == 0 ? 1 : 0; 1190} 1191 1192sub _is_even { 1193 # return true if arg is even 1194 $_[1]->[0] & 1 ? 0 : 1; 1195} 1196 1197sub _is_odd { 1198 # return true if arg is odd 1199 $_[1]->[0] & 1 ? 1 : 0; 1200} 1201 1202sub _is_one { 1203 # return true if arg is one 1204 @{$_[1]} == 1 && $_[1]->[0] == 1 ? 1 : 0; 1205} 1206 1207sub _is_two { 1208 # return true if arg is two 1209 @{$_[1]} == 1 && $_[1]->[0] == 2 ? 1 : 0; 1210} 1211 1212sub _is_ten { 1213 # return true if arg is ten 1214 @{$_[1]} == 1 && $_[1]->[0] == 10 ? 1 : 0; 1215} 1216 1217sub __strip_zeros { 1218 # Internal normalization function that strips leading zeros from the array. 1219 # Args: ref to array 1220 my $x = shift; 1221 1222 push @$x, 0 if @$x == 0; # div might return empty results, so fix it 1223 return $x if @$x == 1; # early out 1224 1225 #print "strip: cnt $cnt i $i\n"; 1226 # '0', '3', '4', '0', '0', 1227 # 0 1 2 3 4 1228 # cnt = 5, i = 4 1229 # i = 4 1230 # i = 3 1231 # => fcnt = cnt - i (5-2 => 3, cnt => 5-1 = 4, throw away from 4th pos) 1232 # >= 1: skip first part (this can be zero) 1233 1234 my $i = $#$x; 1235 while ($i > 0) { 1236 last if $x->[$i] != 0; 1237 $i--; 1238 } 1239 $i++; 1240 splice(@$x, $i) if $i < @$x; 1241 $x; 1242} 1243 1244############################################################################### 1245# check routine to test internal state for corruptions 1246 1247sub _check { 1248 # used by the test suite 1249 my ($class, $x) = @_; 1250 1251 my $msg = $class -> SUPER::_check($x); 1252 return $msg if $msg; 1253 1254 my $n; 1255 eval { $n = @$x }; 1256 return "Not an array reference" unless $@ eq ''; 1257 1258 return "Reference to an empty array" unless $n > 0; 1259 1260 # The following fails with Math::BigInt::FastCalc because a 1261 # Math::BigInt::FastCalc "object" is an unblessed array ref. 1262 # 1263 #return 0 unless ref($x) eq $class; 1264 1265 for (my $i = 0 ; $i <= $#$x ; ++ $i) { 1266 my $e = $x -> [$i]; 1267 1268 return "Element at index $i is undefined" 1269 unless defined $e; 1270 1271 return "Element at index $i is a '" . ref($e) . 1272 "', which is not a scalar" 1273 unless ref($e) eq ""; 1274 1275 # It would be better to use the regex /^([1-9]\d*|0)\z/, but that fails 1276 # in Math::BigInt::FastCalc, because it sometimes creates array 1277 # elements like "000000". 1278 return "Element at index $i is '$e', which does not look like an" . 1279 " normal integer" unless $e =~ /^\d+\z/; 1280 1281 return "Element at index $i is '$e', which is not smaller than" . 1282 " the base '$BASE'" if $e >= $BASE; 1283 1284 return "Element at index $i (last element) is zero" 1285 if $#$x > 0 && $i == $#$x && $e == 0; 1286 } 1287 1288 return 0; 1289} 1290 1291############################################################################### 1292 1293sub _mod { 1294 # if possible, use mod shortcut 1295 my ($c, $x, $yo) = @_; 1296 1297 # slow way since $y too big 1298 if (@$yo > 1) { 1299 my ($xo, $rem) = $c->_div($x, $yo); 1300 @$x = @$rem; 1301 return $x; 1302 } 1303 1304 my $y = $yo->[0]; 1305 1306 # if both are single element arrays 1307 if (@$x == 1) { 1308 $x->[0] %= $y; 1309 return $x; 1310 } 1311 1312 # if @$x has more than one element, but @$y is a single element 1313 my $b = $BASE % $y; 1314 if ($b == 0) { 1315 # when BASE % Y == 0 then (B * BASE) % Y == 0 1316 # (B * BASE) % $y + A % Y => A % Y 1317 # so need to consider only last element: O(1) 1318 $x->[0] %= $y; 1319 } elsif ($b == 1) { 1320 # else need to go through all elements in @$x: O(N), but loop is a bit 1321 # simplified 1322 my $r = 0; 1323 foreach (@$x) { 1324 $r = ($r + $_) % $y; # not much faster, but heh... 1325 #$r += $_ % $y; $r %= $y; 1326 } 1327 $r = 0 if $r == $y; 1328 $x->[0] = $r; 1329 } else { 1330 # else need to go through all elements in @$x: O(N) 1331 my $r = 0; 1332 my $bm = 1; 1333 foreach (@$x) { 1334 $r = ($_ * $bm + $r) % $y; 1335 $bm = ($bm * $b) % $y; 1336 1337 #$r += ($_ % $y) * $bm; 1338 #$bm *= $b; 1339 #$bm %= $y; 1340 #$r %= $y; 1341 } 1342 $r = 0 if $r == $y; 1343 $x->[0] = $r; 1344 } 1345 @$x = $x->[0]; # keep one element of @$x 1346 return $x; 1347} 1348 1349############################################################################## 1350# shifts 1351 1352sub _rsft { 1353 my ($c, $x, $y, $n) = @_; 1354 1355 if ($n != 10) { 1356 $n = $c->_new($n); 1357 return scalar $c->_div($x, $c->_pow($n, $y)); 1358 } 1359 1360 # shortcut (faster) for shifting by 10) 1361 # multiples of $BASE_LEN 1362 my $dst = 0; # destination 1363 my $src = $c->_num($y); # as normal int 1364 my $xlen = (@$x - 1) * $BASE_LEN + length(int($x->[-1])); 1365 if ($src >= $xlen or ($src == $xlen and !defined $x->[1])) { 1366 # 12345 67890 shifted right by more than 10 digits => 0 1367 splice(@$x, 1); # leave only one element 1368 $x->[0] = 0; # set to zero 1369 return $x; 1370 } 1371 my $rem = $src % $BASE_LEN; # remainder to shift 1372 $src = int($src / $BASE_LEN); # source 1373 if ($rem == 0) { 1374 splice(@$x, 0, $src); # even faster, 38.4 => 39.3 1375 } else { 1376 my $len = @$x - $src; # elems to go 1377 my $vd; 1378 my $z = '0' x $BASE_LEN; 1379 $x->[ @$x ] = 0; # avoid || 0 test inside loop 1380 while ($dst < $len) { 1381 $vd = $z . $x->[$src]; 1382 $vd = substr($vd, -$BASE_LEN, $BASE_LEN - $rem); 1383 $src++; 1384 $vd = substr($z . $x->[$src], -$rem, $rem) . $vd; 1385 $vd = substr($vd, -$BASE_LEN, $BASE_LEN) if length($vd) > $BASE_LEN; 1386 $x->[$dst] = int($vd); 1387 $dst++; 1388 } 1389 splice(@$x, $dst) if $dst > 0; # kill left-over array elems 1390 pop @$x if $x->[-1] == 0 && @$x > 1; # kill last element if 0 1391 } # else rem == 0 1392 $x; 1393} 1394 1395sub _lsft { 1396 my ($c, $x, $n, $b) = @_; 1397 1398 return $x if $c->_is_zero($x); 1399 1400 # Handle the special case when the base is a power of 10. Don't check 1401 # whether log($b)/log(10) is an integer, because log(1000)/log(10) is not 1402 # exactly 3. 1403 1404 my $log10 = sprintf "%.0f", log($b) / log(10); 1405 if ($b == 10 ** $log10) { 1406 $b = 10; 1407 $n = $c->_mul($n, $c->_new($log10)); 1408 1409 # shortcut (faster) for shifting by 10) since we are in base 10eX 1410 # multiples of $BASE_LEN: 1411 my $src = @$x; # source 1412 my $len = $c->_num($n); # shift-len as normal int 1413 my $rem = $len % $BASE_LEN; # remainder to shift 1414 my $dst = $src + int($len / $BASE_LEN); # destination 1415 my $vd; # further speedup 1416 $x->[$src] = 0; # avoid first ||0 for speed 1417 my $z = '0' x $BASE_LEN; 1418 while ($src >= 0) { 1419 $vd = $x->[$src]; 1420 $vd = $z . $vd; 1421 $vd = substr($vd, -$BASE_LEN + $rem, $BASE_LEN - $rem); 1422 $vd .= $src > 0 ? substr($z . $x->[$src - 1], -$BASE_LEN, $rem) 1423 : '0' x $rem; 1424 $vd = substr($vd, -$BASE_LEN, $BASE_LEN) if length($vd) > $BASE_LEN; 1425 $x->[$dst] = int($vd); 1426 $dst--; 1427 $src--; 1428 } 1429 # set lowest parts to 0 1430 while ($dst >= 0) { 1431 $x->[$dst--] = 0; 1432 } 1433 # fix spurious last zero element 1434 splice @$x, -1 if $x->[-1] == 0; 1435 return $x; 1436 } else { 1437 $b = $c->_new($b); 1438 #print $c->_str($b); 1439 return $c->_mul($x, $c->_pow($b, $n)); 1440 } 1441} 1442 1443sub _pow { 1444 # power of $x to $y 1445 # ref to array, ref to array, return ref to array 1446 my ($c, $cx, $cy) = @_; 1447 1448 if (@$cy == 1 && $cy->[0] == 0) { 1449 splice(@$cx, 1); 1450 $cx->[0] = 1; # y == 0 => x => 1 1451 return $cx; 1452 } 1453 1454 if ((@$cx == 1 && $cx->[0] == 1) || # x == 1 1455 (@$cy == 1 && $cy->[0] == 1)) # or y == 1 1456 { 1457 return $cx; 1458 } 1459 1460 if (@$cx == 1 && $cx->[0] == 0) { 1461 splice (@$cx, 1); 1462 $cx->[0] = 0; # 0 ** y => 0 (if not y <= 0) 1463 return $cx; 1464 } 1465 1466 my $pow2 = $c->_one(); 1467 1468 my $y_bin = $c->_as_bin($cy); 1469 $y_bin =~ s/^0b//; 1470 my $len = length($y_bin); 1471 while (--$len > 0) { 1472 $c->_mul($pow2, $cx) if substr($y_bin, $len, 1) eq '1'; # is odd? 1473 $c->_mul($cx, $cx); 1474 } 1475 1476 $c->_mul($cx, $pow2); 1477 $cx; 1478} 1479 1480sub _nok { 1481 # Return binomial coefficient (n over k). 1482 # Given refs to arrays, return ref to array. 1483 # First input argument is modified. 1484 1485 my ($c, $n, $k) = @_; 1486 1487 # If k > n/2, or, equivalently, 2*k > n, compute nok(n, k) as 1488 # nok(n, n-k), to minimize the number if iterations in the loop. 1489 1490 { 1491 my $twok = $c->_mul($c->_two(), $c->_copy($k)); # 2 * k 1492 if ($c->_acmp($twok, $n) > 0) { # if 2*k > n 1493 $k = $c->_sub($c->_copy($n), $k); # k = n - k 1494 } 1495 } 1496 1497 # Example: 1498 # 1499 # / 7 \ 7! 1*2*3*4 * 5*6*7 5 * 6 * 7 6 7 1500 # | | = --------- = --------------- = --------- = 5 * - * - 1501 # \ 3 / (7-3)! 3! 1*2*3*4 * 1*2*3 1 * 2 * 3 2 3 1502 1503 if ($c->_is_zero($k)) { 1504 @$n = 1; 1505 } else { 1506 1507 # Make a copy of the original n, since we'll be modifying n in-place. 1508 1509 my $n_orig = $c->_copy($n); 1510 1511 # n = 5, f = 6, d = 2 (cf. example above) 1512 1513 $c->_sub($n, $k); 1514 $c->_inc($n); 1515 1516 my $f = $c->_copy($n); 1517 $c->_inc($f); 1518 1519 my $d = $c->_two(); 1520 1521 # while f <= n (the original n, that is) ... 1522 1523 while ($c->_acmp($f, $n_orig) <= 0) { 1524 1525 # n = (n * f / d) == 5 * 6 / 2 (cf. example above) 1526 1527 $c->_mul($n, $f); 1528 $c->_div($n, $d); 1529 1530 # f = 7, d = 3 (cf. example above) 1531 1532 $c->_inc($f); 1533 $c->_inc($d); 1534 } 1535 1536 } 1537 1538 return $n; 1539} 1540 1541my @factorials = ( 1542 1, 1543 1, 1544 2, 1545 2*3, 1546 2*3*4, 1547 2*3*4*5, 1548 2*3*4*5*6, 1549 2*3*4*5*6*7, 1550 ); 1551 1552sub _fac { 1553 # factorial of $x 1554 # ref to array, return ref to array 1555 my ($c, $cx) = @_; 1556 1557 if ((@$cx == 1) && ($cx->[0] <= 7)) { 1558 $cx->[0] = $factorials[$cx->[0]]; # 0 => 1, 1 => 1, 2 => 2 etc. 1559 return $cx; 1560 } 1561 1562 if ((@$cx == 1) && # we do this only if $x >= 12 and $x <= 7000 1563 ($cx->[0] >= 12 && $cx->[0] < 7000)) { 1564 1565 # Calculate (k-j) * (k-j+1) ... k .. (k+j-1) * (k + j) 1566 # See http://blogten.blogspot.com/2007/01/calculating-n.html 1567 # The above series can be expressed as factors: 1568 # k * k - (j - i) * 2 1569 # We cache k*k, and calculate (j * j) as the sum of the first j odd integers 1570 1571 # This will not work when N exceeds the storage of a Perl scalar, however, 1572 # in this case the algorithm would be way too slow to terminate, anyway. 1573 1574 # As soon as the last element of $cx is 0, we split it up and remember 1575 # how many zeors we got so far. The reason is that n! will accumulate 1576 # zeros at the end rather fast. 1577 my $zero_elements = 0; 1578 1579 # If n is even, set n = n -1 1580 my $k = $c->_num($cx); 1581 my $even = 1; 1582 if (($k & 1) == 0) { 1583 $even = $k; 1584 $k --; 1585 } 1586 # set k to the center point 1587 $k = ($k + 1) / 2; 1588 # print "k $k even: $even\n"; 1589 # now calculate k * k 1590 my $k2 = $k * $k; 1591 my $odd = 1; 1592 my $sum = 1; 1593 my $i = $k - 1; 1594 # keep reference to x 1595 my $new_x = $c->_new($k * $even); 1596 @$cx = @$new_x; 1597 if ($cx->[0] == 0) { 1598 $zero_elements ++; 1599 shift @$cx; 1600 } 1601 # print STDERR "x = ", $c->_str($cx), "\n"; 1602 my $BASE2 = int(sqrt($BASE))-1; 1603 my $j = 1; 1604 while ($j <= $i) { 1605 my $m = ($k2 - $sum); 1606 $odd += 2; 1607 $sum += $odd; 1608 $j++; 1609 while ($j <= $i && ($m < $BASE2) && (($k2 - $sum) < $BASE2)) { 1610 $m *= ($k2 - $sum); 1611 $odd += 2; 1612 $sum += $odd; 1613 $j++; 1614 # print STDERR "\n k2 $k2 m $m sum $sum odd $odd\n"; sleep(1); 1615 } 1616 if ($m < $BASE) { 1617 $c->_mul($cx, [$m]); 1618 } else { 1619 $c->_mul($cx, $c->_new($m)); 1620 } 1621 if ($cx->[0] == 0) { 1622 $zero_elements ++; 1623 shift @$cx; 1624 } 1625 # print STDERR "Calculate $k2 - $sum = $m (x = ", $c->_str($cx), ")\n"; 1626 } 1627 # multiply in the zeros again 1628 unshift @$cx, (0) x $zero_elements; 1629 return $cx; 1630 } 1631 1632 # go forward until $base is exceeded limit is either $x steps (steps == 100 1633 # means a result always too high) or $base. 1634 my $steps = 100; 1635 $steps = $cx->[0] if @$cx == 1; 1636 my $r = 2; 1637 my $cf = 3; 1638 my $step = 2; 1639 my $last = $r; 1640 while ($r * $cf < $BASE && $step < $steps) { 1641 $last = $r; 1642 $r *= $cf++; 1643 $step++; 1644 } 1645 if ((@$cx == 1) && $step == $cx->[0]) { 1646 # completely done, so keep reference to $x and return 1647 $cx->[0] = $r; 1648 return $cx; 1649 } 1650 1651 # now we must do the left over steps 1652 my $n; # steps still to do 1653 if (@$cx == 1) { 1654 $n = $cx->[0]; 1655 } else { 1656 $n = $c->_copy($cx); 1657 } 1658 1659 # Set $cx to the last result below $BASE (but keep ref to $x) 1660 $cx->[0] = $last; 1661 splice (@$cx, 1); 1662 # As soon as the last element of $cx is 0, we split it up and remember 1663 # how many zeors we got so far. The reason is that n! will accumulate 1664 # zeros at the end rather fast. 1665 my $zero_elements = 0; 1666 1667 # do left-over steps fit into a scalar? 1668 if (ref $n eq 'ARRAY') { 1669 # No, so use slower inc() & cmp() 1670 # ($n is at least $BASE here) 1671 my $base_2 = int(sqrt($BASE)) - 1; 1672 #print STDERR "base_2: $base_2\n"; 1673 while ($step < $base_2) { 1674 if ($cx->[0] == 0) { 1675 $zero_elements ++; 1676 shift @$cx; 1677 } 1678 my $b = $step * ($step + 1); 1679 $step += 2; 1680 $c->_mul($cx, [$b]); 1681 } 1682 $step = [$step]; 1683 while ($c->_acmp($step, $n) <= 0) { 1684 if ($cx->[0] == 0) { 1685 $zero_elements ++; 1686 shift @$cx; 1687 } 1688 $c->_mul($cx, $step); 1689 $c->_inc($step); 1690 } 1691 } else { 1692 # Yes, so we can speed it up slightly 1693 1694 # print "# left over steps $n\n"; 1695 1696 my $base_4 = int(sqrt(sqrt($BASE))) - 2; 1697 #print STDERR "base_4: $base_4\n"; 1698 my $n4 = $n - 4; 1699 while ($step < $n4 && $step < $base_4) { 1700 if ($cx->[0] == 0) { 1701 $zero_elements ++; 1702 shift @$cx; 1703 } 1704 my $b = $step * ($step + 1); 1705 $step += 2; 1706 $b *= $step * ($step + 1); 1707 $step += 2; 1708 $c->_mul($cx, [$b]); 1709 } 1710 my $base_2 = int(sqrt($BASE)) - 1; 1711 my $n2 = $n - 2; 1712 #print STDERR "base_2: $base_2\n"; 1713 while ($step < $n2 && $step < $base_2) { 1714 if ($cx->[0] == 0) { 1715 $zero_elements ++; 1716 shift @$cx; 1717 } 1718 my $b = $step * ($step + 1); 1719 $step += 2; 1720 $c->_mul($cx, [$b]); 1721 } 1722 # do what's left over 1723 while ($step <= $n) { 1724 $c->_mul($cx, [$step]); 1725 $step++; 1726 if ($cx->[0] == 0) { 1727 $zero_elements ++; 1728 shift @$cx; 1729 } 1730 } 1731 } 1732 # multiply in the zeros again 1733 unshift @$cx, (0) x $zero_elements; 1734 $cx; # return result 1735} 1736 1737sub _log_int { 1738 # calculate integer log of $x to base $base 1739 # ref to array, ref to array - return ref to array 1740 my ($c, $x, $base) = @_; 1741 1742 # X == 0 => NaN 1743 return if @$x == 1 && $x->[0] == 0; 1744 1745 # BASE 0 or 1 => NaN 1746 return if @$base == 1 && $base->[0] < 2; 1747 1748 # X == 1 => 0 (is exact) 1749 if (@$x == 1 && $x->[0] == 1) { 1750 @$x = 0; 1751 return $x, 1; 1752 } 1753 1754 my $cmp = $c->_acmp($x, $base); 1755 1756 # X == BASE => 1 (is exact) 1757 if ($cmp == 0) { 1758 @$x = 1; 1759 return $x, 1; 1760 } 1761 1762 # 1 < X < BASE => 0 (is truncated) 1763 if ($cmp < 0) { 1764 @$x = 0; 1765 return $x, 0; 1766 } 1767 1768 my $x_org = $c->_copy($x); # preserve x 1769 1770 # Compute a guess for the result based on: 1771 # $guess = int ( length_in_base_10(X) / ( log(base) / log(10) ) ) 1772 my $len = $c->_len($x_org); 1773 my $log = log($base->[-1]) / log(10); 1774 1775 # for each additional element in $base, we add $BASE_LEN to the result, 1776 # based on the observation that log($BASE, 10) is BASE_LEN and 1777 # log(x*y) == log(x) + log(y): 1778 $log += (@$base - 1) * $BASE_LEN; 1779 1780 # calculate now a guess based on the values obtained above: 1781 my $res = int($len / $log); 1782 1783 @$x = $res; 1784 my $trial = $c->_pow($c->_copy($base), $x); 1785 my $acmp = $c->_acmp($trial, $x_org); 1786 1787 # Did we get the exact result? 1788 1789 return $x, 1 if $acmp == 0; 1790 1791 # Too small? 1792 1793 while ($acmp < 0) { 1794 $c->_mul($trial, $base); 1795 $c->_inc($x); 1796 $acmp = $c->_acmp($trial, $x_org); 1797 } 1798 1799 # Too big? 1800 1801 while ($acmp > 0) { 1802 $c->_div($trial, $base); 1803 $c->_dec($x); 1804 $acmp = $c->_acmp($trial, $x_org); 1805 } 1806 1807 return $x, 1 if $acmp == 0; # result is exact 1808 return $x, 0; # result is too small 1809} 1810 1811# for debugging: 1812use constant DEBUG => 0; 1813my $steps = 0; 1814sub steps { $steps }; 1815 1816sub _sqrt { 1817 # square-root of $x in place 1818 # Compute a guess of the result (by rule of thumb), then improve it via 1819 # Newton's method. 1820 my ($c, $x) = @_; 1821 1822 if (@$x == 1) { 1823 # fits into one Perl scalar, so result can be computed directly 1824 $x->[0] = int(sqrt($x->[0])); 1825 return $x; 1826 } 1827 my $y = $c->_copy($x); 1828 # hopefully _len/2 is < $BASE, the -1 is to always undershot the guess 1829 # since our guess will "grow" 1830 my $l = int(($c->_len($x)-1) / 2); 1831 1832 my $lastelem = $x->[-1]; # for guess 1833 my $elems = @$x - 1; 1834 # not enough digits, but could have more? 1835 if ((length($lastelem) <= 3) && ($elems > 1)) { 1836 # right-align with zero pad 1837 my $len = length($lastelem) & 1; 1838 print "$lastelem => " if DEBUG; 1839 $lastelem .= substr($x->[-2] . '0' x $BASE_LEN, 0, $BASE_LEN); 1840 # former odd => make odd again, or former even to even again 1841 $lastelem = $lastelem / 10 if (length($lastelem) & 1) != $len; 1842 print "$lastelem\n" if DEBUG; 1843 } 1844 1845 # construct $x (instead of $c->_lsft($x, $l, 10) 1846 my $r = $l % $BASE_LEN; # 10000 00000 00000 00000 ($BASE_LEN=5) 1847 $l = int($l / $BASE_LEN); 1848 print "l = $l " if DEBUG; 1849 1850 splice @$x, $l; # keep ref($x), but modify it 1851 1852 # we make the first part of the guess not '1000...0' but int(sqrt($lastelem)) 1853 # that gives us: 1854 # 14400 00000 => sqrt(14400) => guess first digits to be 120 1855 # 144000 000000 => sqrt(144000) => guess 379 1856 1857 print "$lastelem (elems $elems) => " if DEBUG; 1858 $lastelem = $lastelem / 10 if ($elems & 1 == 1); # odd or even? 1859 my $g = sqrt($lastelem); 1860 $g =~ s/\.//; # 2.345 => 2345 1861 $r -= 1 if $elems & 1 == 0; # 70 => 7 1862 1863 # padd with zeros if result is too short 1864 $x->[$l--] = int(substr($g . '0' x $r, 0, $r+1)); 1865 print "now ", $x->[-1] if DEBUG; 1866 print " would have been ", int('1' . '0' x $r), "\n" if DEBUG; 1867 1868 # If @$x > 1, we could compute the second elem of the guess, too, to create 1869 # an even better guess. Not implemented yet. Does it improve performance? 1870 $x->[$l--] = 0 while ($l >= 0); # all other digits of guess are zero 1871 1872 print "start x= ", $c->_str($x), "\n" if DEBUG; 1873 my $two = $c->_two(); 1874 my $last = $c->_zero(); 1875 my $lastlast = $c->_zero(); 1876 $steps = 0 if DEBUG; 1877 while ($c->_acmp($last, $x) != 0 && $c->_acmp($lastlast, $x) != 0) { 1878 $steps++ if DEBUG; 1879 $lastlast = $c->_copy($last); 1880 $last = $c->_copy($x); 1881 $c->_add($x, $c->_div($c->_copy($y), $x)); 1882 $c->_div($x, $two ); 1883 print " x= ", $c->_str($x), "\n" if DEBUG; 1884 } 1885 print "\nsteps in sqrt: $steps, " if DEBUG; 1886 $c->_dec($x) if $c->_acmp($y, $c->_mul($c->_copy($x), $x)) < 0; # overshot? 1887 print " final ", $x->[-1], "\n" if DEBUG; 1888 $x; 1889} 1890 1891sub _root { 1892 # Take n'th root of $x in place. 1893 1894 my ($c, $x, $n) = @_; 1895 1896 # Small numbers. 1897 1898 if (@$x == 1 && @$n == 1) { 1899 # Result can be computed directly. Adjust initial result for numerical 1900 # errors, e.g., int(1000**(1/3)) is 2, not 3. 1901 my $y = int($x->[0] ** (1 / $n->[0])); 1902 my $yp1 = $y + 1; 1903 $y = $yp1 if $yp1 ** $n->[0] == $x->[0]; 1904 $x->[0] = $y; 1905 return $x; 1906 } 1907 1908 # If x <= n, the result is always (truncated to) 1. 1909 1910 if ((@$x > 1 || $x -> [0] > 0) && # if x is non-zero ... 1911 $c -> _acmp($x, $n) <= 0) # ... and x <= n 1912 { 1913 my $one = $x -> _one(); 1914 @$x = @$one; 1915 return $x; 1916 } 1917 1918 # If $n is a power of two, take sqrt($x) repeatedly, e.g., root($x, 4) = 1919 # sqrt(sqrt($x)), root($x, 8) = sqrt(sqrt(sqrt($x))). 1920 1921 my $b = $c -> _as_bin($n); 1922 if ($b =~ /0b1(0+)$/) { 1923 my $count = length($1); # 0b100 => len('00') => 2 1924 my $cnt = $count; # counter for loop 1925 unshift @$x, 0; # add one element, together with one 1926 # more below in the loop this makes 2 1927 while ($cnt-- > 0) { 1928 # 'Inflate' $x by adding one element, basically computing 1929 # $x * $BASE * $BASE. This gives us more $BASE_LEN digits for 1930 # result since len(sqrt($X)) approx == len($x) / 2. 1931 unshift @$x, 0; 1932 # Calculate sqrt($x), $x is now one element to big, again. In the 1933 # next round we make that two, again. 1934 $c -> _sqrt($x); 1935 } 1936 1937 # $x is now one element too big, so truncate result by removing it. 1938 shift @$x; 1939 1940 return $x; 1941 } 1942 1943 my $DEBUG = 0; 1944 1945 # Now the general case. This works by finding an initial guess. If this 1946 # guess is incorrect, a relatively small delta is chosen. This delta is 1947 # used to find a lower and upper limit for the correct value. The delta is 1948 # doubled in each iteration. When a lower and upper limit is found, 1949 # bisection is applied to narrow down the region until we have the correct 1950 # value. 1951 1952 # Split x into mantissa and exponent in base 10, so that 1953 # 1954 # x = xm * 10^xe, where 0 < xm < 1 and xe is an integer 1955 1956 my $x_str = $c -> _str($x); 1957 my $xm = "." . $x_str; 1958 my $xe = length($x_str); 1959 1960 # From this we compute the base 10 logarithm of x 1961 # 1962 # log_10(x) = log_10(xm) + log_10(xe^10) 1963 # = log(xm)/log(10) + xe 1964 # 1965 # and then the base 10 logarithm of y, where y = x^(1/n) 1966 # 1967 # log_10(y) = log_10(x)/n 1968 1969 my $log10x = log($xm) / log(10) + $xe; 1970 my $log10y = $log10x / $c -> _num($n); 1971 1972 # And from this we compute ym and ye, the mantissa and exponent (in 1973 # base 10) of y, where 1 < ym <= 10 and ye is an integer. 1974 1975 my $ye = int $log10y; 1976 my $ym = 10 ** ($log10y - $ye); 1977 1978 # Finally, we scale the mantissa and exponent to incraese the integer 1979 # part of ym, before building the string representing our guess of y. 1980 1981 if ($DEBUG) { 1982 print "\n"; 1983 print "xm = $xm\n"; 1984 print "xe = $xe\n"; 1985 print "log10x = $log10x\n"; 1986 print "log10y = $log10y\n"; 1987 print "ym = $ym\n"; 1988 print "ye = $ye\n"; 1989 print "\n"; 1990 } 1991 1992 my $d = $ye < 15 ? $ye : 15; 1993 $ym *= 10 ** $d; 1994 $ye -= $d; 1995 1996 my $y_str = sprintf('%.0f', $ym) . "0" x $ye; 1997 my $y = $c -> _new($y_str); 1998 1999 if ($DEBUG) { 2000 print "ym = $ym\n"; 2001 print "ye = $ye\n"; 2002 print "\n"; 2003 print "y_str = $y_str (initial guess)\n"; 2004 print "\n"; 2005 } 2006 2007 # See if our guess y is correct. 2008 2009 my $trial = $c -> _pow($c -> _copy($y), $n); 2010 my $acmp = $c -> _acmp($trial, $x); 2011 2012 if ($acmp == 0) { 2013 @$x = @$y; 2014 return $x; 2015 } 2016 2017 # Find a lower and upper limit for the correct value of y. Start off with a 2018 # delta value that is approximately the size of the accuracy of the guess. 2019 2020 my $lower; 2021 my $upper; 2022 2023 my $delta = $c -> _new("1" . ("0" x $ye)); 2024 my $two = $c -> _two(); 2025 2026 if ($acmp < 0) { 2027 $lower = $y; 2028 while ($acmp < 0) { 2029 $upper = $c -> _add($c -> _copy($lower), $delta); 2030 2031 if ($DEBUG) { 2032 print "lower = $lower\n"; 2033 print "upper = $upper\n"; 2034 print "delta = $delta\n"; 2035 print "\n"; 2036 } 2037 $acmp = $c -> _acmp($c -> _pow($c -> _copy($upper), $n), $x); 2038 if ($acmp == 0) { 2039 @$x = @$upper; 2040 return $x; 2041 } 2042 $delta = $c -> _mul($delta, $two); 2043 } 2044 } 2045 2046 elsif ($acmp > 0) { 2047 $upper = $y; 2048 my $zero = $c -> _zero(); 2049 while ($acmp > 0) { 2050 if ($c -> _acmp($upper, $delta) <= 0) { 2051 $lower = $c -> _zero(); 2052 last; 2053 } 2054 $lower = $c -> _sub($c -> _copy($upper), $delta); 2055 2056 if ($DEBUG) { 2057 print "lower = $lower\n"; 2058 print "upper = $upper\n"; 2059 print "delta = $delta\n"; 2060 print "\n"; 2061 } 2062 $acmp = $c -> _acmp($c -> _pow($c -> _copy($lower), $n), $x); 2063 if ($acmp == 0) { 2064 @$x = @$lower; 2065 return $x; 2066 } 2067 $delta = $c -> _mul($delta, $two); 2068 } 2069 } 2070 2071 # Use bisection to narrow down the interval. 2072 2073 my $one = $c -> _one(); 2074 { 2075 2076 $delta = $c -> _sub($c -> _copy($upper), $lower); 2077 if ($c -> _acmp($delta, $one) <= 0) { 2078 @$x = @$lower; 2079 return $x; 2080 } 2081 2082 if ($DEBUG) { 2083 print "lower = $lower\n"; 2084 print "upper = $upper\n"; 2085 print "delta = $delta\n"; 2086 print "\n"; 2087 } 2088 2089 $delta = $c -> _div($delta, $two); 2090 my $middle = $c -> _add($c -> _copy($lower), $delta); 2091 2092 $acmp = $c -> _acmp($c -> _pow($c -> _copy($middle), $n), $x); 2093 if ($acmp < 0) { 2094 $lower = $middle; 2095 } elsif ($acmp > 0) { 2096 $upper = $middle; 2097 } else { 2098 @$x = @$middle; 2099 return $x; 2100 } 2101 2102 redo; 2103 } 2104 2105 $x; 2106} 2107 2108############################################################################## 2109# binary stuff 2110 2111sub _and { 2112 my ($c, $x, $y) = @_; 2113 2114 # the shortcut makes equal, large numbers _really_ fast, and makes only a 2115 # very small performance drop for small numbers (e.g. something with less 2116 # than 32 bit) Since we optimize for large numbers, this is enabled. 2117 return $x if $c->_acmp($x, $y) == 0; # shortcut 2118 2119 my $m = $c->_one(); 2120 my ($xr, $yr); 2121 my $mask = $AND_MASK; 2122 2123 my $x1 = $c->_copy($x); 2124 my $y1 = $c->_copy($y); 2125 my $z = $c->_zero(); 2126 2127 use integer; 2128 until ($c->_is_zero($x1) || $c->_is_zero($y1)) { 2129 ($x1, $xr) = $c->_div($x1, $mask); 2130 ($y1, $yr) = $c->_div($y1, $mask); 2131 2132 $c->_add($z, $c->_mul([ 0 + $xr->[0] & 0 + $yr->[0] ], $m)); 2133 $c->_mul($m, $mask); 2134 } 2135 2136 @$x = @$z; 2137 return $x; 2138} 2139 2140sub _xor { 2141 my ($c, $x, $y) = @_; 2142 2143 return $c->_zero() if $c->_acmp($x, $y) == 0; # shortcut (see -and) 2144 2145 my $m = $c->_one(); 2146 my ($xr, $yr); 2147 my $mask = $XOR_MASK; 2148 2149 my $x1 = $c->_copy($x); 2150 my $y1 = $c->_copy($y); # make copy 2151 my $z = $c->_zero(); 2152 2153 use integer; 2154 until ($c->_is_zero($x1) || $c->_is_zero($y1)) { 2155 ($x1, $xr) = $c->_div($x1, $mask); 2156 ($y1, $yr) = $c->_div($y1, $mask); 2157 # make ints() from $xr, $yr (see _and()) 2158 #$b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; } 2159 #$b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; } 2160 #$c->_add($x, $c->_mul($c->_new($xrr ^ $yrr)), $m) ); 2161 2162 $c->_add($z, $c->_mul([ 0 + $xr->[0] ^ 0 + $yr->[0] ], $m)); 2163 $c->_mul($m, $mask); 2164 } 2165 # the loop stops when the shorter of the two numbers is exhausted 2166 # the remainder of the longer one will survive bit-by-bit, so we simple 2167 # multiply-add it in 2168 $c->_add($z, $c->_mul($x1, $m) ) if !$c->_is_zero($x1); 2169 $c->_add($z, $c->_mul($y1, $m) ) if !$c->_is_zero($y1); 2170 2171 @$x = @$z; 2172 return $x; 2173} 2174 2175sub _or { 2176 my ($c, $x, $y) = @_; 2177 2178 return $x if $c->_acmp($x, $y) == 0; # shortcut (see _and) 2179 2180 my $m = $c->_one(); 2181 my ($xr, $yr); 2182 my $mask = $OR_MASK; 2183 2184 my $x1 = $c->_copy($x); 2185 my $y1 = $c->_copy($y); # make copy 2186 my $z = $c->_zero(); 2187 2188 use integer; 2189 until ($c->_is_zero($x1) || $c->_is_zero($y1)) { 2190 ($x1, $xr) = $c->_div($x1, $mask); 2191 ($y1, $yr) = $c->_div($y1, $mask); 2192 # make ints() from $xr, $yr (see _and()) 2193 # $b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; } 2194 # $b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; } 2195 # $c->_add($x, $c->_mul(_new( $c, ($xrr | $yrr) ), $m) ); 2196 2197 $c->_add($z, $c->_mul([ 0 + $xr->[0] | 0 + $yr->[0] ], $m)); 2198 $c->_mul($m, $mask); 2199 } 2200 # the loop stops when the shorter of the two numbers is exhausted 2201 # the remainder of the longer one will survive bit-by-bit, so we simple 2202 # multiply-add it in 2203 $c->_add($z, $c->_mul($x1, $m) ) if !$c->_is_zero($x1); 2204 $c->_add($z, $c->_mul($y1, $m) ) if !$c->_is_zero($y1); 2205 2206 @$x = @$z; 2207 return $x; 2208} 2209 2210sub _as_hex { 2211 # convert a decimal number to hex (ref to array, return ref to string) 2212 my ($c, $x) = @_; 2213 2214 # fits into one element (handle also 0x0 case) 2215 return sprintf("0x%x", $x->[0]) if @$x == 1; 2216 2217 my $x1 = $c->_copy($x); 2218 2219 my $es = ''; 2220 my ($xr, $h, $x10000); 2221 if ($] >= 5.006) { 2222 $x10000 = [ 0x10000 ]; 2223 $h = 'h4'; 2224 } else { 2225 $x10000 = [ 0x1000 ]; 2226 $h = 'h3'; 2227 } 2228 while (@$x1 != 1 || $x1->[0] != 0) # _is_zero() 2229 { 2230 ($x1, $xr) = $c->_div($x1, $x10000); 2231 $es .= unpack($h, pack('V', $xr->[0])); 2232 } 2233 $es = reverse $es; 2234 $es =~ s/^[0]+//; # strip leading zeros 2235 '0x' . $es; # return result prepended with 0x 2236} 2237 2238sub _as_bin { 2239 # convert a decimal number to bin (ref to array, return ref to string) 2240 my ($c, $x) = @_; 2241 2242 # fits into one element (and Perl recent enough), handle also 0b0 case 2243 # handle zero case for older Perls 2244 if ($] <= 5.005 && @$x == 1 && $x->[0] == 0) { 2245 my $t = '0b0'; 2246 return $t; 2247 } 2248 if (@$x == 1 && $] >= 5.006) { 2249 my $t = sprintf("0b%b", $x->[0]); 2250 return $t; 2251 } 2252 my $x1 = $c->_copy($x); 2253 2254 my $es = ''; 2255 my ($xr, $b, $x10000); 2256 if ($] >= 5.006) { 2257 $x10000 = [ 0x10000 ]; 2258 $b = 'b16'; 2259 } else { 2260 $x10000 = [ 0x1000 ]; 2261 $b = 'b12'; 2262 } 2263 while (!(@$x1 == 1 && $x1->[0] == 0)) # _is_zero() 2264 { 2265 ($x1, $xr) = $c->_div($x1, $x10000); 2266 $es .= unpack($b, pack('v', $xr->[0])); 2267 } 2268 $es = reverse $es; 2269 $es =~ s/^[0]+//; # strip leading zeros 2270 '0b' . $es; # return result prepended with 0b 2271} 2272 2273sub _as_oct { 2274 # convert a decimal number to octal (ref to array, return ref to string) 2275 my ($c, $x) = @_; 2276 2277 # fits into one element (handle also 0 case) 2278 return sprintf("0%o", $x->[0]) if @$x == 1; 2279 2280 my $x1 = $c->_copy($x); 2281 2282 my $es = ''; 2283 my $xr; 2284 my $x1000 = [ 0100000 ]; 2285 while (@$x1 != 1 || $x1->[0] != 0) # _is_zero() 2286 { 2287 ($x1, $xr) = $c->_div($x1, $x1000); 2288 $es .= reverse sprintf("%05o", $xr->[0]); 2289 } 2290 $es = reverse $es; 2291 $es =~ s/^0+//; # strip leading zeros 2292 '0' . $es; # return result prepended with 0 2293} 2294 2295sub _from_oct { 2296 # convert a octal number to decimal (string, return ref to array) 2297 my ($c, $os) = @_; 2298 2299 # for older Perls, play safe 2300 my $m = [ 0100000 ]; 2301 my $d = 5; # 5 digits at a time 2302 2303 my $mul = $c->_one(); 2304 my $x = $c->_zero(); 2305 2306 my $len = int((length($os) - 1) / $d); # $d digit parts, w/o the '0' 2307 my $val; 2308 my $i = -$d; 2309 while ($len >= 0) { 2310 $val = substr($os, $i, $d); # get oct digits 2311 $val = CORE::oct($val); 2312 $i -= $d; 2313 $len --; 2314 my $adder = [ $val ]; 2315 $c->_add($x, $c->_mul($adder, $mul)) if $val != 0; 2316 $c->_mul($mul, $m) if $len >= 0; # skip last mul 2317 } 2318 $x; 2319} 2320 2321sub _from_hex { 2322 # convert a hex number to decimal (string, return ref to array) 2323 my ($c, $hs) = @_; 2324 2325 my $m = $c->_new(0x10000000); # 28 bit at a time (<32 bit!) 2326 my $d = 7; # 7 digits at a time 2327 my $mul = $c->_one(); 2328 my $x = $c->_zero(); 2329 2330 my $len = int((length($hs) - 2) / $d); # $d digit parts, w/o the '0x' 2331 my $val; 2332 my $i = -$d; 2333 while ($len >= 0) { 2334 $val = substr($hs, $i, $d); # get hex digits 2335 $val =~ s/^0x// if $len == 0; # for last part only because 2336 $val = CORE::hex($val); # hex does not like wrong chars 2337 $i -= $d; 2338 $len --; 2339 my $adder = [ $val ]; 2340 # if the resulting number was to big to fit into one element, create a 2341 # two-element version (bug found by Mark Lakata - Thanx!) 2342 if (CORE::length($val) > $BASE_LEN) { 2343 $adder = $c->_new($val); 2344 } 2345 $c->_add($x, $c->_mul($adder, $mul)) if $val != 0; 2346 $c->_mul($mul, $m) if $len >= 0; # skip last mul 2347 } 2348 $x; 2349} 2350 2351sub _from_bin { 2352 # convert a hex number to decimal (string, return ref to array) 2353 my ($c, $bs) = @_; 2354 2355 # instead of converting X (8) bit at a time, it is faster to "convert" the 2356 # number to hex, and then call _from_hex. 2357 2358 my $hs = $bs; 2359 $hs =~ s/^[+-]?0b//; # remove sign and 0b 2360 my $l = length($hs); # bits 2361 $hs = '0' x (8 - ($l % 8)) . $hs if ($l % 8) != 0; # padd left side w/ 0 2362 my $h = '0x' . unpack('H*', pack ('B*', $hs)); # repack as hex 2363 2364 $c->_from_hex($h); 2365} 2366 2367############################################################################## 2368# special modulus functions 2369 2370sub _modinv { 2371 # modular multiplicative inverse 2372 my ($c, $x, $y) = @_; 2373 2374 # modulo zero 2375 if ($c->_is_zero($y)) { 2376 return undef, undef; 2377 } 2378 2379 # modulo one 2380 if ($c->_is_one($y)) { 2381 return $c->_zero(), '+'; 2382 } 2383 2384 my $u = $c->_zero(); 2385 my $v = $c->_one(); 2386 my $a = $c->_copy($y); 2387 my $b = $c->_copy($x); 2388 2389 # Euclid's Algorithm for bgcd(), only that we calc bgcd() ($a) and the result 2390 # ($u) at the same time. See comments in BigInt for why this works. 2391 my $q; 2392 my $sign = 1; 2393 { 2394 ($a, $q, $b) = ($b, $c->_div($a, $b)); # step 1 2395 last if $c->_is_zero($b); 2396 2397 my $t = $c->_add( # step 2: 2398 $c->_mul($c->_copy($v), $q), # t = v * q 2399 $u); # + u 2400 $u = $v; # u = v 2401 $v = $t; # v = t 2402 $sign = -$sign; 2403 redo; 2404 } 2405 2406 # if the gcd is not 1, then return NaN 2407 return (undef, undef) unless $c->_is_one($a); 2408 2409 ($v, $sign == 1 ? '+' : '-'); 2410} 2411 2412sub _modpow { 2413 # modulus of power ($x ** $y) % $z 2414 my ($c, $num, $exp, $mod) = @_; 2415 2416 # a^b (mod 1) = 0 for all a and b 2417 if ($c->_is_one($mod)) { 2418 @$num = 0; 2419 return $num; 2420 } 2421 2422 # 0^a (mod m) = 0 if m != 0, a != 0 2423 # 0^0 (mod m) = 1 if m != 0 2424 if ($c->_is_zero($num)) { 2425 if ($c->_is_zero($exp)) { 2426 @$num = 1; 2427 } else { 2428 @$num = 0; 2429 } 2430 return $num; 2431 } 2432 2433 # $num = $c->_mod($num, $mod); # this does not make it faster 2434 2435 my $acc = $c->_copy($num); 2436 my $t = $c->_one(); 2437 2438 my $expbin = $c->_as_bin($exp); 2439 $expbin =~ s/^0b//; 2440 my $len = length($expbin); 2441 while (--$len >= 0) { 2442 if (substr($expbin, $len, 1) eq '1') { # is_odd 2443 $t = $c->_mul($t, $acc); 2444 $t = $c->_mod($t, $mod); 2445 } 2446 $acc = $c->_mul($acc, $acc); 2447 $acc = $c->_mod($acc, $mod); 2448 } 2449 @$num = @$t; 2450 $num; 2451} 2452 2453sub _gcd { 2454 # Greatest common divisor. 2455 2456 my ($c, $x, $y) = @_; 2457 2458 # gcd(0, 0) = 0 2459 # gcd(0, a) = a, if a != 0 2460 2461 if (@$x == 1 && $x->[0] == 0) { 2462 if (@$y == 1 && $y->[0] == 0) { 2463 @$x = 0; 2464 } else { 2465 @$x = @$y; 2466 } 2467 return $x; 2468 } 2469 2470 # Until $y is zero ... 2471 2472 until (@$y == 1 && $y->[0] == 0) { 2473 2474 # Compute remainder. 2475 2476 $c->_mod($x, $y); 2477 2478 # Swap $x and $y. 2479 2480 my $tmp = $c->_copy($x); 2481 @$x = @$y; 2482 $y = $tmp; # no deref here; that would modify input $y 2483 } 2484 2485 return $x; 2486} 2487 24881; 2489 2490=pod 2491 2492=head1 NAME 2493 2494Math::BigInt::Calc - Pure Perl module to support Math::BigInt 2495 2496=head1 SYNOPSIS 2497 2498 # to use it with Math::BigInt 2499 use Math::BigInt lib => 'Calc'; 2500 2501 # to use it with Math::BigFloat 2502 use Math::BigFloat lib => 'Calc'; 2503 2504 # to use it with Math::BigRat 2505 use Math::BigRat lib => 'Calc'; 2506 2507=head1 DESCRIPTION 2508 2509Math::BigInt::Calc inherits from Math::BigInt::Lib. 2510 2511In this library, the numbers are represented in base B = 10**N, where N is the 2512largest possible value that does not cause overflow in the intermediate 2513computations. The base B elements are stored in an array, with the least 2514significant element stored in array element zero. There are no leading zero 2515elements, except a single zero element when the number is zero. 2516 2517For instance, if B = 10000, the number 1234567890 is represented internally 2518as [7890, 3456, 12]. 2519 2520=head1 SEE ALSO 2521 2522L<Math::BigInt::Lib> for a description of the API. 2523 2524Alternative libraries L<Math::BigInt::FastCalc>, L<Math::BigInt::GMP>, and 2525L<Math::BigInt::Pari>. 2526 2527Some of the modules that use these libraries L<Math::BigInt>, 2528L<Math::BigFloat>, and L<Math::BigRat>. 2529 2530=cut 2531