/extlib/Math/BigInt/Calc.pm

http://github.com/openmelody/melody · Perl · 2610 lines · 1844 code · 298 blank · 468 comment · 576 complexity · 6c3e35292b0d47638547b913642afc41 MD5 · raw file

Large files are truncated click here to view the full file

  1. package Math::BigInt::Calc;
  2. use 5.006002;
  3. use strict;
  4. # use warnings; # dont use warnings for older Perls
  5. our $VERSION = '0.56';
  6. # Package to store unsigned big integers in decimal and do math with them
  7. # Internally the numbers are stored in an array with at least 1 element, no
  8. # leading zero parts (except the first) and in base 1eX where X is determined
  9. # automatically at loading time to be the maximum possible value
  10. # todo:
  11. # - fully remove funky $# stuff in div() (maybe - that code scares me...)
  12. # USE_MUL: due to problems on certain os (os390, posix-bc) "* 1e-5" is used
  13. # instead of "/ 1e5" at some places, (marked with USE_MUL). Other platforms
  14. # BS2000, some Crays need USE_DIV instead.
  15. # The BEGIN block is used to determine which of the two variants gives the
  16. # correct result.
  17. # Beware of things like:
  18. # $i = $i * $y + $car; $car = int($i / $BASE); $i = $i % $BASE;
  19. # This works on x86, but fails on ARM (SA1100, iPAQ) due to whoknows what
  20. # reasons. So, use this instead (slower, but correct):
  21. # $i = $i * $y + $car; $car = int($i / $BASE); $i -= $BASE * $car;
  22. ##############################################################################
  23. # global constants, flags and accessory
  24. # announce that we are compatible with MBI v1.83 and up
  25. sub api_version () { 2; }
  26. # constants for easier life
  27. my ($BASE,$BASE_LEN,$RBASE,$MAX_VAL);
  28. my ($AND_BITS,$XOR_BITS,$OR_BITS);
  29. my ($AND_MASK,$XOR_MASK,$OR_MASK);
  30. sub _base_len
  31. {
  32. # Set/get the BASE_LEN and assorted other, connected values.
  33. # Used only by the testsuite, the set variant is used only by the BEGIN
  34. # block below:
  35. shift;
  36. my ($b, $int) = @_;
  37. if (defined $b)
  38. {
  39. # avoid redefinitions
  40. undef &_mul;
  41. undef &_div;
  42. if ($] >= 5.008 && $int && $b > 7)
  43. {
  44. $BASE_LEN = $b;
  45. *_mul = \&_mul_use_div_64;
  46. *_div = \&_div_use_div_64;
  47. $BASE = int("1e".$BASE_LEN);
  48. $MAX_VAL = $BASE-1;
  49. return $BASE_LEN unless wantarray;
  50. return ($BASE_LEN, $BASE, $AND_BITS, $XOR_BITS, $OR_BITS, $BASE_LEN, $MAX_VAL,);
  51. }
  52. # find whether we can use mul or div in mul()/div()
  53. $BASE_LEN = $b+1;
  54. my $caught = 0;
  55. while (--$BASE_LEN > 5)
  56. {
  57. $BASE = int("1e".$BASE_LEN);
  58. $RBASE = abs('1e-'.$BASE_LEN); # see USE_MUL
  59. $caught = 0;
  60. $caught += 1 if (int($BASE * $RBASE) != 1); # should be 1
  61. $caught += 2 if (int($BASE / $BASE) != 1); # should be 1
  62. last if $caught != 3;
  63. }
  64. $BASE = int("1e".$BASE_LEN);
  65. $RBASE = abs('1e-'.$BASE_LEN); # see USE_MUL
  66. $MAX_VAL = $BASE-1;
  67. # ($caught & 1) != 0 => cannot use MUL
  68. # ($caught & 2) != 0 => cannot use DIV
  69. if ($caught == 2) # 2
  70. {
  71. # must USE_MUL since we cannot use DIV
  72. *_mul = \&_mul_use_mul;
  73. *_div = \&_div_use_mul;
  74. }
  75. else # 0 or 1
  76. {
  77. # can USE_DIV instead
  78. *_mul = \&_mul_use_div;
  79. *_div = \&_div_use_div;
  80. }
  81. }
  82. return $BASE_LEN unless wantarray;
  83. return ($BASE_LEN, $BASE, $AND_BITS, $XOR_BITS, $OR_BITS, $BASE_LEN, $MAX_VAL);
  84. }
  85. sub _new
  86. {
  87. # (ref to string) return ref to num_array
  88. # Convert a number from string format (without sign) to internal base
  89. # 1ex format. Assumes normalized value as input.
  90. my $il = length($_[1])-1;
  91. # < BASE_LEN due len-1 above
  92. return [ int($_[1]) ] if $il < $BASE_LEN; # shortcut for short numbers
  93. # this leaves '00000' instead of int 0 and will be corrected after any op
  94. [ reverse(unpack("a" . ($il % $BASE_LEN+1)
  95. . ("a$BASE_LEN" x ($il / $BASE_LEN)), $_[1])) ];
  96. }
  97. BEGIN
  98. {
  99. # from Daniel Pfeiffer: determine largest group of digits that is precisely
  100. # multipliable with itself plus carry
  101. # Test now changed to expect the proper pattern, not a result off by 1 or 2
  102. my ($e, $num) = 3; # lowest value we will use is 3+1-1 = 3
  103. do
  104. {
  105. $num = ('9' x ++$e) + 0;
  106. $num *= $num + 1.0;
  107. } while ("$num" =~ /9{$e}0{$e}/); # must be a certain pattern
  108. $e--; # last test failed, so retract one step
  109. # the limits below brush the problems with the test above under the rug:
  110. # the test should be able to find the proper $e automatically
  111. $e = 5 if $^O =~ /^uts/; # UTS get's some special treatment
  112. $e = 5 if $^O =~ /^unicos/; # unicos is also problematic (6 seems to work
  113. # there, but we play safe)
  114. my $int = 0;
  115. if ($e > 7)
  116. {
  117. use integer;
  118. my $e1 = 7;
  119. $num = 7;
  120. do
  121. {
  122. $num = ('9' x ++$e1) + 0;
  123. $num *= $num + 1;
  124. } while ("$num" =~ /9{$e1}0{$e1}/); # must be a certain pattern
  125. $e1--; # last test failed, so retract one step
  126. if ($e1 > 7)
  127. {
  128. $int = 1; $e = $e1;
  129. }
  130. }
  131. __PACKAGE__->_base_len($e,$int); # set and store
  132. use integer;
  133. # find out how many bits _and, _or and _xor can take (old default = 16)
  134. # I don't think anybody has yet 128 bit scalars, so let's play safe.
  135. local $^W = 0; # don't warn about 'nonportable number'
  136. $AND_BITS = 15; $XOR_BITS = 15; $OR_BITS = 15;
  137. # find max bits, we will not go higher than numberofbits that fit into $BASE
  138. # to make _and etc simpler (and faster for smaller, slower for large numbers)
  139. my $max = 16;
  140. while (2 ** $max < $BASE) { $max++; }
  141. {
  142. no integer;
  143. $max = 16 if $] < 5.006; # older Perls might not take >16 too well
  144. }
  145. my ($x,$y,$z);
  146. do {
  147. $AND_BITS++;
  148. $x = CORE::oct('0b' . '1' x $AND_BITS); $y = $x & $x;
  149. $z = (2 ** $AND_BITS) - 1;
  150. } while ($AND_BITS < $max && $x == $z && $y == $x);
  151. $AND_BITS --; # retreat one step
  152. do {
  153. $XOR_BITS++;
  154. $x = CORE::oct('0b' . '1' x $XOR_BITS); $y = $x ^ 0;
  155. $z = (2 ** $XOR_BITS) - 1;
  156. } while ($XOR_BITS < $max && $x == $z && $y == $x);
  157. $XOR_BITS --; # retreat one step
  158. do {
  159. $OR_BITS++;
  160. $x = CORE::oct('0b' . '1' x $OR_BITS); $y = $x | $x;
  161. $z = (2 ** $OR_BITS) - 1;
  162. } while ($OR_BITS < $max && $x == $z && $y == $x);
  163. $OR_BITS --; # retreat one step
  164. $AND_MASK = __PACKAGE__->_new( ( 2 ** $AND_BITS ));
  165. $XOR_MASK = __PACKAGE__->_new( ( 2 ** $XOR_BITS ));
  166. $OR_MASK = __PACKAGE__->_new( ( 2 ** $OR_BITS ));
  167. # We can compute the approximate lenght no faster than the real length:
  168. *_alen = \&_len;
  169. }
  170. ###############################################################################
  171. sub _zero
  172. {
  173. # create a zero
  174. [ 0 ];
  175. }
  176. sub _one
  177. {
  178. # create a one
  179. [ 1 ];
  180. }
  181. sub _two
  182. {
  183. # create a two (used internally for shifting)
  184. [ 2 ];
  185. }
  186. sub _ten
  187. {
  188. # create a 10 (used internally for shifting)
  189. [ 10 ];
  190. }
  191. sub _1ex
  192. {
  193. # create a 1Ex
  194. my $rem = $_[1] % $BASE_LEN; # remainder
  195. my $parts = $_[1] / $BASE_LEN; # parts
  196. # 000000, 000000, 100
  197. [ (0) x $parts, '1' . ('0' x $rem) ];
  198. }
  199. sub _copy
  200. {
  201. # make a true copy
  202. [ @{$_[1]} ];
  203. }
  204. # catch and throw away
  205. sub import { }
  206. ##############################################################################
  207. # convert back to string and number
  208. sub _str
  209. {
  210. # (ref to BINT) return num_str
  211. # Convert number from internal base 100000 format to string format.
  212. # internal format is always normalized (no leading zeros, "-0" => "+0")
  213. my $ar = $_[1];
  214. my $l = scalar @$ar; # number of parts
  215. if ($l < 1) # should not happen
  216. {
  217. require Carp;
  218. Carp::croak("$_[1] has no elements");
  219. }
  220. my $ret = "";
  221. # handle first one different to strip leading zeros from it (there are no
  222. # leading zero parts in internal representation)
  223. $l --; $ret .= int($ar->[$l]); $l--;
  224. # Interestingly, the pre-padd method uses more time
  225. # the old grep variant takes longer (14 vs. 10 sec)
  226. my $z = '0' x ($BASE_LEN-1);
  227. while ($l >= 0)
  228. {
  229. $ret .= substr($z.$ar->[$l],-$BASE_LEN); # fastest way I could think of
  230. $l--;
  231. }
  232. $ret;
  233. }
  234. sub _num
  235. {
  236. # Make a number (scalar int/float) from a BigInt object
  237. my $x = $_[1];
  238. return 0+$x->[0] if scalar @$x == 1; # below $BASE
  239. my $fac = 1;
  240. my $num = 0;
  241. foreach (@$x)
  242. {
  243. $num += $fac*$_; $fac *= $BASE;
  244. }
  245. $num;
  246. }
  247. ##############################################################################
  248. # actual math code
  249. sub _add
  250. {
  251. # (ref to int_num_array, ref to int_num_array)
  252. # routine to add two base 1eX numbers
  253. # stolen from Knuth Vol 2 Algorithm A pg 231
  254. # there are separate routines to add and sub as per Knuth pg 233
  255. # This routine clobbers up array x, but not y.
  256. my ($c,$x,$y) = @_;
  257. return $x if (@$y == 1) && $y->[0] == 0; # $x + 0 => $x
  258. if ((@$x == 1) && $x->[0] == 0) # 0 + $y => $y->copy
  259. {
  260. # twice as slow as $x = [ @$y ], but nec. to retain $x as ref :(
  261. @$x = @$y; return $x;
  262. }
  263. # for each in Y, add Y to X and carry. If after that, something is left in
  264. # X, foreach in X add carry to X and then return X, carry
  265. # Trades one "$j++" for having to shift arrays
  266. my $i; my $car = 0; my $j = 0;
  267. for $i (@$y)
  268. {
  269. $x->[$j] -= $BASE if $car = (($x->[$j] += $i + $car) >= $BASE) ? 1 : 0;
  270. $j++;
  271. }
  272. while ($car != 0)
  273. {
  274. $x->[$j] -= $BASE if $car = (($x->[$j] += $car) >= $BASE) ? 1 : 0; $j++;
  275. }
  276. $x;
  277. }
  278. sub _inc
  279. {
  280. # (ref to int_num_array, ref to int_num_array)
  281. # Add 1 to $x, modify $x in place
  282. my ($c,$x) = @_;
  283. for my $i (@$x)
  284. {
  285. return $x if (($i += 1) < $BASE); # early out
  286. $i = 0; # overflow, next
  287. }
  288. push @$x,1 if (($x->[-1] || 0) == 0); # last overflowed, so extend
  289. $x;
  290. }
  291. sub _dec
  292. {
  293. # (ref to int_num_array, ref to int_num_array)
  294. # Sub 1 from $x, modify $x in place
  295. my ($c,$x) = @_;
  296. my $MAX = $BASE-1; # since MAX_VAL based on BASE
  297. for my $i (@$x)
  298. {
  299. last if (($i -= 1) >= 0); # early out
  300. $i = $MAX; # underflow, next
  301. }
  302. pop @$x if $x->[-1] == 0 && @$x > 1; # last underflowed (but leave 0)
  303. $x;
  304. }
  305. sub _sub
  306. {
  307. # (ref to int_num_array, ref to int_num_array, swap)
  308. # subtract base 1eX numbers -- stolen from Knuth Vol 2 pg 232, $x > $y
  309. # subtract Y from X by modifying x in place
  310. my ($c,$sx,$sy,$s) = @_;
  311. my $car = 0; my $i; my $j = 0;
  312. if (!$s)
  313. {
  314. for $i (@$sx)
  315. {
  316. last unless defined $sy->[$j] || $car;
  317. $i += $BASE if $car = (($i -= ($sy->[$j] || 0) + $car) < 0); $j++;
  318. }
  319. # might leave leading zeros, so fix that
  320. return __strip_zeros($sx);
  321. }
  322. for $i (@$sx)
  323. {
  324. # we can't do an early out if $x is < than $y, since we
  325. # need to copy the high chunks from $y. Found by Bob Mathews.
  326. #last unless defined $sy->[$j] || $car;
  327. $sy->[$j] += $BASE
  328. if $car = (($sy->[$j] = $i-($sy->[$j]||0) - $car) < 0);
  329. $j++;
  330. }
  331. # might leave leading zeros, so fix that
  332. __strip_zeros($sy);
  333. }
  334. sub _mul_use_mul
  335. {
  336. # (ref to int_num_array, ref to int_num_array)
  337. # multiply two numbers in internal representation
  338. # modifies first arg, second need not be different from first
  339. my ($c,$xv,$yv) = @_;
  340. if (@$yv == 1)
  341. {
  342. # shortcut for two very short numbers (improved by Nathan Zook)
  343. # works also if xv and yv are the same reference, and handles also $x == 0
  344. if (@$xv == 1)
  345. {
  346. if (($xv->[0] *= $yv->[0]) >= $BASE)
  347. {
  348. $xv->[0] = $xv->[0] - ($xv->[1] = int($xv->[0] * $RBASE)) * $BASE;
  349. };
  350. return $xv;
  351. }
  352. # $x * 0 => 0
  353. if ($yv->[0] == 0)
  354. {
  355. @$xv = (0);
  356. return $xv;
  357. }
  358. # multiply a large number a by a single element one, so speed up
  359. my $y = $yv->[0]; my $car = 0;
  360. foreach my $i (@$xv)
  361. {
  362. $i = $i * $y + $car; $car = int($i * $RBASE); $i -= $car * $BASE;
  363. }
  364. push @$xv, $car if $car != 0;
  365. return $xv;
  366. }
  367. # shortcut for result $x == 0 => result = 0
  368. return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) );
  369. # since multiplying $x with $x fails, make copy in this case
  370. $yv = [@$xv] if $xv == $yv; # same references?
  371. my @prod = (); my ($prod,$car,$cty,$xi,$yi);
  372. for $xi (@$xv)
  373. {
  374. $car = 0; $cty = 0;
  375. # slow variant
  376. # for $yi (@$yv)
  377. # {
  378. # $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  379. # $prod[$cty++] =
  380. # $prod - ($car = int($prod * RBASE)) * $BASE; # see USE_MUL
  381. # }
  382. # $prod[$cty] += $car if $car; # need really to check for 0?
  383. # $xi = shift @prod;
  384. # faster variant
  385. # looping through this if $xi == 0 is silly - so optimize it away!
  386. $xi = (shift @prod || 0), next if $xi == 0;
  387. for $yi (@$yv)
  388. {
  389. $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  390. ## this is actually a tad slower
  391. ## $prod = $prod[$cty]; $prod += ($car + $xi * $yi); # no ||0 here
  392. $prod[$cty++] =
  393. $prod - ($car = int($prod * $RBASE)) * $BASE; # see USE_MUL
  394. }
  395. $prod[$cty] += $car if $car; # need really to check for 0?
  396. $xi = shift @prod || 0; # || 0 makes v5.005_3 happy
  397. }
  398. push @$xv, @prod;
  399. # can't have leading zeros
  400. # __strip_zeros($xv);
  401. $xv;
  402. }
  403. sub _mul_use_div_64
  404. {
  405. # (ref to int_num_array, ref to int_num_array)
  406. # multiply two numbers in internal representation
  407. # modifies first arg, second need not be different from first
  408. # works for 64 bit integer with "use integer"
  409. my ($c,$xv,$yv) = @_;
  410. use integer;
  411. if (@$yv == 1)
  412. {
  413. # shortcut for two small numbers, also handles $x == 0
  414. if (@$xv == 1)
  415. {
  416. # shortcut for two very short numbers (improved by Nathan Zook)
  417. # works also if xv and yv are the same reference, and handles also $x == 0
  418. if (($xv->[0] *= $yv->[0]) >= $BASE)
  419. {
  420. $xv->[0] =
  421. $xv->[0] - ($xv->[1] = $xv->[0] / $BASE) * $BASE;
  422. };
  423. return $xv;
  424. }
  425. # $x * 0 => 0
  426. if ($yv->[0] == 0)
  427. {
  428. @$xv = (0);
  429. return $xv;
  430. }
  431. # multiply a large number a by a single element one, so speed up
  432. my $y = $yv->[0]; my $car = 0;
  433. foreach my $i (@$xv)
  434. {
  435. #$i = $i * $y + $car; $car = $i / $BASE; $i -= $car * $BASE;
  436. $i = $i * $y + $car; $i -= ($car = $i / $BASE) * $BASE;
  437. }
  438. push @$xv, $car if $car != 0;
  439. return $xv;
  440. }
  441. # shortcut for result $x == 0 => result = 0
  442. return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) );
  443. # since multiplying $x with $x fails, make copy in this case
  444. $yv = [@$xv] if $xv == $yv; # same references?
  445. my @prod = (); my ($prod,$car,$cty,$xi,$yi);
  446. for $xi (@$xv)
  447. {
  448. $car = 0; $cty = 0;
  449. # looping through this if $xi == 0 is silly - so optimize it away!
  450. $xi = (shift @prod || 0), next if $xi == 0;
  451. for $yi (@$yv)
  452. {
  453. $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  454. $prod[$cty++] = $prod - ($car = $prod / $BASE) * $BASE;
  455. }
  456. $prod[$cty] += $car if $car; # need really to check for 0?
  457. $xi = shift @prod || 0; # || 0 makes v5.005_3 happy
  458. }
  459. push @$xv, @prod;
  460. $xv;
  461. }
  462. sub _mul_use_div
  463. {
  464. # (ref to int_num_array, ref to int_num_array)
  465. # multiply two numbers in internal representation
  466. # modifies first arg, second need not be different from first
  467. my ($c,$xv,$yv) = @_;
  468. if (@$yv == 1)
  469. {
  470. # shortcut for two small numbers, also handles $x == 0
  471. if (@$xv == 1)
  472. {
  473. # shortcut for two very short numbers (improved by Nathan Zook)
  474. # works also if xv and yv are the same reference, and handles also $x == 0
  475. if (($xv->[0] *= $yv->[0]) >= $BASE)
  476. {
  477. $xv->[0] =
  478. $xv->[0] - ($xv->[1] = int($xv->[0] / $BASE)) * $BASE;
  479. };
  480. return $xv;
  481. }
  482. # $x * 0 => 0
  483. if ($yv->[0] == 0)
  484. {
  485. @$xv = (0);
  486. return $xv;
  487. }
  488. # multiply a large number a by a single element one, so speed up
  489. my $y = $yv->[0]; my $car = 0;
  490. foreach my $i (@$xv)
  491. {
  492. $i = $i * $y + $car; $car = int($i / $BASE); $i -= $car * $BASE;
  493. # This (together with use integer;) does not work on 32-bit Perls
  494. #$i = $i * $y + $car; $i -= ($car = $i / $BASE) * $BASE;
  495. }
  496. push @$xv, $car if $car != 0;
  497. return $xv;
  498. }
  499. # shortcut for result $x == 0 => result = 0
  500. return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) );
  501. # since multiplying $x with $x fails, make copy in this case
  502. $yv = [@$xv] if $xv == $yv; # same references?
  503. my @prod = (); my ($prod,$car,$cty,$xi,$yi);
  504. for $xi (@$xv)
  505. {
  506. $car = 0; $cty = 0;
  507. # looping through this if $xi == 0 is silly - so optimize it away!
  508. $xi = (shift @prod || 0), next if $xi == 0;
  509. for $yi (@$yv)
  510. {
  511. $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
  512. $prod[$cty++] = $prod - ($car = int($prod / $BASE)) * $BASE;
  513. }
  514. $prod[$cty] += $car if $car; # need really to check for 0?
  515. $xi = shift @prod || 0; # || 0 makes v5.005_3 happy
  516. }
  517. push @$xv, @prod;
  518. # can't have leading zeros
  519. # __strip_zeros($xv);
  520. $xv;
  521. }
  522. sub _div_use_mul
  523. {
  524. # ref to array, ref to array, modify first array and return remainder if
  525. # in list context
  526. # see comments in _div_use_div() for more explanations
  527. my ($c,$x,$yorg) = @_;
  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. # This works, because we store the numbers in a chunked format where each
  531. # element contains 5..7 digits (depending on system).
  532. # if both numbers have only one element:
  533. if (@$x == 1 && @$yorg == 1)
  534. {
  535. # shortcut, $yorg and $x are two small numbers
  536. if (wantarray)
  537. {
  538. my $r = [ $x->[0] % $yorg->[0] ];
  539. $x->[0] = int($x->[0] / $yorg->[0]);
  540. return ($x,$r);
  541. }
  542. else
  543. {
  544. $x->[0] = int($x->[0] / $yorg->[0]);
  545. return $x;
  546. }
  547. }
  548. # if x has more than one, but y has only one element:
  549. if (@$yorg == 1)
  550. {
  551. my $rem;
  552. $rem = _mod($c,[ @$x ],$yorg) if wantarray;
  553. # shortcut, $y is < $BASE
  554. my $j = scalar @$x; my $r = 0;
  555. my $y = $yorg->[0]; my $b;
  556. while ($j-- > 0)
  557. {
  558. $b = $r * $BASE + $x->[$j];
  559. $x->[$j] = int($b/$y);
  560. $r = $b % $y;
  561. }
  562. pop @$x if @$x > 1 && $x->[-1] == 0; # splice up a leading zero
  563. return ($x,$rem) if wantarray;
  564. return $x;
  565. }
  566. # now x and y have more than one element
  567. # check whether y has more elements than x, if yet, the result will be 0
  568. if (@$yorg > @$x)
  569. {
  570. my $rem;
  571. $rem = [@$x] if wantarray; # make copy
  572. splice (@$x,1); # keep ref to original array
  573. $x->[0] = 0; # set to 0
  574. return ($x,$rem) if wantarray; # including remainder?
  575. return $x; # only x, which is [0] now
  576. }
  577. # check whether the numbers have the same number of elements, in that case
  578. # the result will fit into one element and can be computed efficiently
  579. if (@$yorg == @$x)
  580. {
  581. my $rem;
  582. # if $yorg has more digits than $x (it's leading element is longer than
  583. # the one from $x), the result will also be 0:
  584. if (length(int($yorg->[-1])) > length(int($x->[-1])))
  585. {
  586. $rem = [@$x] if wantarray; # make copy
  587. splice (@$x,1); # keep ref to org array
  588. $x->[0] = 0; # set to 0
  589. return ($x,$rem) if wantarray; # including remainder?
  590. return $x;
  591. }
  592. # now calculate $x / $yorg
  593. if (length(int($yorg->[-1])) == length(int($x->[-1])))
  594. {
  595. # same length, so make full compare
  596. my $a = 0; my $j = scalar @$x - 1;
  597. # manual way (abort if unequal, good for early ne)
  598. while ($j >= 0)
  599. {
  600. last if ($a = $x->[$j] - $yorg->[$j]); $j--;
  601. }
  602. # $a contains the result of the compare between X and Y
  603. # a < 0: x < y, a == 0: x == y, a > 0: x > y
  604. if ($a <= 0)
  605. {
  606. $rem = [ 0 ]; # a = 0 => x == y => rem 0
  607. $rem = [@$x] if $a != 0; # a < 0 => x < y => rem = x
  608. splice(@$x,1); # keep single element
  609. $x->[0] = 0; # if $a < 0
  610. $x->[0] = 1 if $a == 0; # $x == $y
  611. return ($x,$rem) if wantarray;
  612. return $x;
  613. }
  614. # $x >= $y, so proceed normally
  615. }
  616. }
  617. # all other cases:
  618. my $y = [ @$yorg ]; # always make copy to preserve
  619. my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);
  620. $car = $bar = $prd = 0;
  621. if (($dd = int($BASE/($y->[-1]+1))) != 1)
  622. {
  623. for $xi (@$x)
  624. {
  625. $xi = $xi * $dd + $car;
  626. $xi -= ($car = int($xi * $RBASE)) * $BASE; # see USE_MUL
  627. }
  628. push(@$x, $car); $car = 0;
  629. for $yi (@$y)
  630. {
  631. $yi = $yi * $dd + $car;
  632. $yi -= ($car = int($yi * $RBASE)) * $BASE; # see USE_MUL
  633. }
  634. }
  635. else
  636. {
  637. push(@$x, 0);
  638. }
  639. @q = (); ($v2,$v1) = @$y[-2,-1];
  640. $v2 = 0 unless $v2;
  641. while ($#$x > $#$y)
  642. {
  643. ($u2,$u1,$u0) = @$x[-3..-1];
  644. $u2 = 0 unless $u2;
  645. #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
  646. # if $v1 == 0;
  647. $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$BASE+$u1)/$v1));
  648. --$q while ($v2*$q > ($u0*$BASE+$u1-$q*$v1)*$BASE+$u2);
  649. if ($q)
  650. {
  651. ($car, $bar) = (0,0);
  652. for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
  653. {
  654. $prd = $q * $y->[$yi] + $car;
  655. $prd -= ($car = int($prd * $RBASE)) * $BASE; # see USE_MUL
  656. $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
  657. }
  658. if ($x->[-1] < $car + $bar)
  659. {
  660. $car = 0; --$q;
  661. for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
  662. {
  663. $x->[$xi] -= $BASE
  664. if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE));
  665. }
  666. }
  667. }
  668. pop(@$x);
  669. unshift(@q, $q);
  670. }
  671. if (wantarray)
  672. {
  673. @d = ();
  674. if ($dd != 1)
  675. {
  676. $car = 0;
  677. for $xi (reverse @$x)
  678. {
  679. $prd = $car * $BASE + $xi;
  680. $car = $prd - ($tmp = int($prd / $dd)) * $dd; # see USE_MUL
  681. unshift(@d, $tmp);
  682. }
  683. }
  684. else
  685. {
  686. @d = @$x;
  687. }
  688. @$x = @q;
  689. my $d = \@d;
  690. __strip_zeros($x);
  691. __strip_zeros($d);
  692. return ($x,$d);
  693. }
  694. @$x = @q;
  695. __strip_zeros($x);
  696. $x;
  697. }
  698. sub _div_use_div_64
  699. {
  700. # ref to array, ref to array, modify first array and return remainder if
  701. # in list context
  702. # This version works on 64 bit integers
  703. my ($c,$x,$yorg) = @_;
  704. use integer;
  705. # the general div algorithmn here is about O(N*N) and thus quite slow, so
  706. # we first check for some special cases and use shortcuts to handle them.
  707. # This works, because we store the numbers in a chunked format where each
  708. # element contains 5..7 digits (depending on system).
  709. # if both numbers have only one element:
  710. if (@$x == 1 && @$yorg == 1)
  711. {
  712. # shortcut, $yorg and $x are two small numbers
  713. if (wantarray)
  714. {
  715. my $r = [ $x->[0] % $yorg->[0] ];
  716. $x->[0] = int($x->[0] / $yorg->[0]);
  717. return ($x,$r);
  718. }
  719. else
  720. {
  721. $x->[0] = int($x->[0] / $yorg->[0]);
  722. return $x;
  723. }
  724. }
  725. # if x has more than one, but y has only one element:
  726. if (@$yorg == 1)
  727. {
  728. my $rem;
  729. $rem = _mod($c,[ @$x ],$yorg) if wantarray;
  730. # shortcut, $y is < $BASE
  731. my $j = scalar @$x; my $r = 0;
  732. my $y = $yorg->[0]; my $b;
  733. while ($j-- > 0)
  734. {
  735. $b = $r * $BASE + $x->[$j];
  736. $x->[$j] = int($b/$y);
  737. $r = $b % $y;
  738. }
  739. pop @$x if @$x > 1 && $x->[-1] == 0; # splice up a leading zero
  740. return ($x,$rem) if wantarray;
  741. return $x;
  742. }
  743. # now x and y have more than one element
  744. # check whether y has more elements than x, if yet, the result will be 0
  745. if (@$yorg > @$x)
  746. {
  747. my $rem;
  748. $rem = [@$x] if wantarray; # make copy
  749. splice (@$x,1); # keep ref to original array
  750. $x->[0] = 0; # set to 0
  751. return ($x,$rem) if wantarray; # including remainder?
  752. return $x; # only x, which is [0] now
  753. }
  754. # check whether the numbers have the same number of elements, in that case
  755. # the result will fit into one element and can be computed efficiently
  756. if (@$yorg == @$x)
  757. {
  758. my $rem;
  759. # if $yorg has more digits than $x (it's leading element is longer than
  760. # the one from $x), the result will also be 0:
  761. if (length(int($yorg->[-1])) > length(int($x->[-1])))
  762. {
  763. $rem = [@$x] if wantarray; # make copy
  764. splice (@$x,1); # keep ref to org array
  765. $x->[0] = 0; # set to 0
  766. return ($x,$rem) if wantarray; # including remainder?
  767. return $x;
  768. }
  769. # now calculate $x / $yorg
  770. if (length(int($yorg->[-1])) == length(int($x->[-1])))
  771. {
  772. # same length, so make full compare
  773. my $a = 0; my $j = scalar @$x - 1;
  774. # manual way (abort if unequal, good for early ne)
  775. while ($j >= 0)
  776. {
  777. last if ($a = $x->[$j] - $yorg->[$j]); $j--;
  778. }
  779. # $a contains the result of the compare between X and Y
  780. # a < 0: x < y, a == 0: x == y, a > 0: x > y
  781. if ($a <= 0)
  782. {
  783. $rem = [ 0 ]; # a = 0 => x == y => rem 0
  784. $rem = [@$x] if $a != 0; # a < 0 => x < y => rem = x
  785. splice(@$x,1); # keep single element
  786. $x->[0] = 0; # if $a < 0
  787. $x->[0] = 1 if $a == 0; # $x == $y
  788. return ($x,$rem) if wantarray; # including remainder?
  789. return $x;
  790. }
  791. # $x >= $y, so proceed normally
  792. }
  793. }
  794. # all other cases:
  795. my $y = [ @$yorg ]; # always make copy to preserve
  796. my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);
  797. $car = $bar = $prd = 0;
  798. if (($dd = int($BASE/($y->[-1]+1))) != 1)
  799. {
  800. for $xi (@$x)
  801. {
  802. $xi = $xi * $dd + $car;
  803. $xi -= ($car = int($xi / $BASE)) * $BASE;
  804. }
  805. push(@$x, $car); $car = 0;
  806. for $yi (@$y)
  807. {
  808. $yi = $yi * $dd + $car;
  809. $yi -= ($car = int($yi / $BASE)) * $BASE;
  810. }
  811. }
  812. else
  813. {
  814. push(@$x, 0);
  815. }
  816. # @q will accumulate the final result, $q contains the current computed
  817. # part of the final result
  818. @q = (); ($v2,$v1) = @$y[-2,-1];
  819. $v2 = 0 unless $v2;
  820. while ($#$x > $#$y)
  821. {
  822. ($u2,$u1,$u0) = @$x[-3..-1];
  823. $u2 = 0 unless $u2;
  824. #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
  825. # if $v1 == 0;
  826. $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$BASE+$u1)/$v1));
  827. --$q while ($v2*$q > ($u0*$BASE+$u1-$q*$v1)*$BASE+$u2);
  828. if ($q)
  829. {
  830. ($car, $bar) = (0,0);
  831. for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
  832. {
  833. $prd = $q * $y->[$yi] + $car;
  834. $prd -= ($car = int($prd / $BASE)) * $BASE;
  835. $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
  836. }
  837. if ($x->[-1] < $car + $bar)
  838. {
  839. $car = 0; --$q;
  840. for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
  841. {
  842. $x->[$xi] -= $BASE
  843. if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE));
  844. }
  845. }
  846. }
  847. pop(@$x); unshift(@q, $q);
  848. }
  849. if (wantarray)
  850. {
  851. @d = ();
  852. if ($dd != 1)
  853. {
  854. $car = 0;
  855. for $xi (reverse @$x)
  856. {
  857. $prd = $car * $BASE + $xi;
  858. $car = $prd - ($tmp = int($prd / $dd)) * $dd;
  859. unshift(@d, $tmp);
  860. }
  861. }
  862. else
  863. {
  864. @d = @$x;
  865. }
  866. @$x = @q;
  867. my $d = \@d;
  868. __strip_zeros($x);
  869. __strip_zeros($d);
  870. return ($x,$d);
  871. }
  872. @$x = @q;
  873. __strip_zeros($x);
  874. $x;
  875. }
  876. sub _div_use_div
  877. {
  878. # ref to array, ref to array, modify first array and return remainder if
  879. # in list context
  880. my ($c,$x,$yorg) = @_;
  881. # the general div algorithmn here is about O(N*N) and thus quite slow, so
  882. # we first check for some special cases and use shortcuts to handle them.
  883. # This works, because we store the numbers in a chunked format where each
  884. # element contains 5..7 digits (depending on system).
  885. # if both numbers have only one element:
  886. if (@$x == 1 && @$yorg == 1)
  887. {
  888. # shortcut, $yorg and $x are two small numbers
  889. if (wantarray)
  890. {
  891. my $r = [ $x->[0] % $yorg->[0] ];
  892. $x->[0] = int($x->[0] / $yorg->[0]);
  893. return ($x,$r);
  894. }
  895. else
  896. {
  897. $x->[0] = int($x->[0] / $yorg->[0]);
  898. return $x;
  899. }
  900. }
  901. # if x has more than one, but y has only one element:
  902. if (@$yorg == 1)
  903. {
  904. my $rem;
  905. $rem = _mod($c,[ @$x ],$yorg) if wantarray;
  906. # shortcut, $y is < $BASE
  907. my $j = scalar @$x; my $r = 0;
  908. my $y = $yorg->[0]; my $b;
  909. while ($j-- > 0)
  910. {
  911. $b = $r * $BASE + $x->[$j];
  912. $x->[$j] = int($b/$y);
  913. $r = $b % $y;
  914. }
  915. pop @$x if @$x > 1 && $x->[-1] == 0; # splice up a leading zero
  916. return ($x,$rem) if wantarray;
  917. return $x;
  918. }
  919. # now x and y have more than one element
  920. # check whether y has more elements than x, if yet, the result will be 0
  921. if (@$yorg > @$x)
  922. {
  923. my $rem;
  924. $rem = [@$x] if wantarray; # make copy
  925. splice (@$x,1); # keep ref to original array
  926. $x->[0] = 0; # set to 0
  927. return ($x,$rem) if wantarray; # including remainder?
  928. return $x; # only x, which is [0] now
  929. }
  930. # check whether the numbers have the same number of elements, in that case
  931. # the result will fit into one element and can be computed efficiently
  932. if (@$yorg == @$x)
  933. {
  934. my $rem;
  935. # if $yorg has more digits than $x (it's leading element is longer than
  936. # the one from $x), the result will also be 0:
  937. if (length(int($yorg->[-1])) > length(int($x->[-1])))
  938. {
  939. $rem = [@$x] if wantarray; # make copy
  940. splice (@$x,1); # keep ref to org array
  941. $x->[0] = 0; # set to 0
  942. return ($x,$rem) if wantarray; # including remainder?
  943. return $x;
  944. }
  945. # now calculate $x / $yorg
  946. if (length(int($yorg->[-1])) == length(int($x->[-1])))
  947. {
  948. # same length, so make full compare
  949. my $a = 0; my $j = scalar @$x - 1;
  950. # manual way (abort if unequal, good for early ne)
  951. while ($j >= 0)
  952. {
  953. last if ($a = $x->[$j] - $yorg->[$j]); $j--;
  954. }
  955. # $a contains the result of the compare between X and Y
  956. # a < 0: x < y, a == 0: x == y, a > 0: x > y
  957. if ($a <= 0)
  958. {
  959. $rem = [ 0 ]; # a = 0 => x == y => rem 0
  960. $rem = [@$x] if $a != 0; # a < 0 => x < y => rem = x
  961. splice(@$x,1); # keep single element
  962. $x->[0] = 0; # if $a < 0
  963. $x->[0] = 1 if $a == 0; # $x == $y
  964. return ($x,$rem) if wantarray; # including remainder?
  965. return $x;
  966. }
  967. # $x >= $y, so proceed normally
  968. }
  969. }
  970. # all other cases:
  971. my $y = [ @$yorg ]; # always make copy to preserve
  972. my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);
  973. $car = $bar = $prd = 0;
  974. if (($dd = int($BASE/($y->[-1]+1))) != 1)
  975. {
  976. for $xi (@$x)
  977. {
  978. $xi = $xi * $dd + $car;
  979. $xi -= ($car = int($xi / $BASE)) * $BASE;
  980. }
  981. push(@$x, $car); $car = 0;
  982. for $yi (@$y)
  983. {
  984. $yi = $yi * $dd + $car;
  985. $yi -= ($car = int($yi / $BASE)) * $BASE;
  986. }
  987. }
  988. else
  989. {
  990. push(@$x, 0);
  991. }
  992. # @q will accumulate the final result, $q contains the current computed
  993. # part of the final result
  994. @q = (); ($v2,$v1) = @$y[-2,-1];
  995. $v2 = 0 unless $v2;
  996. while ($#$x > $#$y)
  997. {
  998. ($u2,$u1,$u0) = @$x[-3..-1];
  999. $u2 = 0 unless $u2;
  1000. #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
  1001. # if $v1 == 0;
  1002. $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$BASE+$u1)/$v1));
  1003. --$q while ($v2*$q > ($u0*$BASE+$u1-$q*$v1)*$BASE+$u2);
  1004. if ($q)
  1005. {
  1006. ($car, $bar) = (0,0);
  1007. for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
  1008. {
  1009. $prd = $q * $y->[$yi] + $car;
  1010. $prd -= ($car = int($prd / $BASE)) * $BASE;
  1011. $x->[$xi] += $BASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
  1012. }
  1013. if ($x->[-1] < $car + $bar)
  1014. {
  1015. $car = 0; --$q;
  1016. for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
  1017. {
  1018. $x->[$xi] -= $BASE
  1019. if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $BASE));
  1020. }
  1021. }
  1022. }
  1023. pop(@$x); unshift(@q, $q);
  1024. }
  1025. if (wantarray)
  1026. {
  1027. @d = ();
  1028. if ($dd != 1)
  1029. {
  1030. $car = 0;
  1031. for $xi (reverse @$x)
  1032. {
  1033. $prd = $car * $BASE + $xi;
  1034. $car = $prd - ($tmp = int($prd / $dd)) * $dd;
  1035. unshift(@d, $tmp);
  1036. }
  1037. }
  1038. else
  1039. {
  1040. @d = @$x;
  1041. }
  1042. @$x = @q;
  1043. my $d = \@d;
  1044. __strip_zeros($x);
  1045. __strip_zeros($d);
  1046. return ($x,$d);
  1047. }
  1048. @$x = @q;
  1049. __strip_zeros($x);
  1050. $x;
  1051. }
  1052. ##############################################################################
  1053. # testing
  1054. sub _acmp
  1055. {
  1056. # internal absolute post-normalized compare (ignore signs)
  1057. # ref to array, ref to array, return <0, 0, >0
  1058. # arrays must have at least one entry; this is not checked for
  1059. my ($c,$cx,$cy) = @_;
  1060. # shortcut for short numbers
  1061. return (($cx->[0] <=> $cy->[0]) <=> 0)
  1062. if scalar @$cx == scalar @$cy && scalar @$cx == 1;
  1063. # fast comp based on number of array elements (aka pseudo-length)
  1064. my $lxy = (scalar @$cx - scalar @$cy)
  1065. # or length of first element if same number of elements (aka difference 0)
  1066. ||
  1067. # need int() here because sometimes the last element is '00018' vs '18'
  1068. (length(int($cx->[-1])) - length(int($cy->[-1])));
  1069. return -1 if $lxy < 0; # already differs, ret
  1070. return 1 if $lxy > 0; # ditto
  1071. # manual way (abort if unequal, good for early ne)
  1072. my $a; my $j = scalar @$cx;
  1073. while (--$j >= 0)
  1074. {
  1075. last if ($a = $cx->[$j] - $cy->[$j]);
  1076. }
  1077. $a <=> 0;
  1078. }
  1079. sub _len
  1080. {
  1081. # compute number of digits in base 10
  1082. # int() because add/sub sometimes leaves strings (like '00005') instead of
  1083. # '5' in this place, thus causing length() to report wrong length
  1084. my $cx = $_[1];
  1085. (@$cx-1)*$BASE_LEN+length(int($cx->[-1]));
  1086. }
  1087. sub _digit
  1088. {
  1089. # return the nth digit, negative values count backward
  1090. # zero is rightmost, so _digit(123,0) will give 3
  1091. my ($c,$x,$n) = @_;
  1092. my $len = _len('',$x);
  1093. $n = $len+$n if $n < 0; # -1 last, -2 second-to-last
  1094. $n = abs($n); # if negative was too big
  1095. $len--; $n = $len if $n > $len; # n to big?
  1096. my $elem = int($n / $BASE_LEN); # which array element
  1097. my $digit = $n % $BASE_LEN; # which digit in this element
  1098. $elem = '0' x $BASE_LEN . @$x[$elem]; # get element padded with 0's
  1099. substr($elem,-$digit-1,1);
  1100. }
  1101. sub _zeros
  1102. {
  1103. # return amount of trailing zeros in decimal
  1104. # check each array elem in _m for having 0 at end as long as elem == 0
  1105. # Upon finding a elem != 0, stop
  1106. my $x = $_[1];
  1107. return 0 if scalar @$x == 1 && $x->[0] == 0;
  1108. my $zeros = 0; my $elem;
  1109. foreach my $e (@$x)
  1110. {
  1111. if ($e != 0)
  1112. {
  1113. $elem = "$e"; # preserve x
  1114. $elem =~ s/.*?(0*$)/$1/; # strip anything not zero
  1115. $zeros *= $BASE_LEN; # elems * 5
  1116. $zeros += length($elem); # count trailing zeros
  1117. last; # early out
  1118. }
  1119. $zeros ++; # real else branch: 50% slower!
  1120. }
  1121. $zeros;
  1122. }
  1123. ##############################################################################
  1124. # _is_* routines
  1125. sub _is_zero
  1126. {
  1127. # return true if arg is zero
  1128. (((scalar @{$_[1]} == 1) && ($_[1]->[0] == 0))) <=> 0;
  1129. }
  1130. sub _is_even
  1131. {
  1132. # return true if arg is even
  1133. (!($_[1]->[0] & 1)) <=> 0;
  1134. }
  1135. sub _is_odd
  1136. {
  1137. # return true if arg is odd
  1138. (($_[1]->[0] & 1)) <=> 0;
  1139. }
  1140. sub _is_one
  1141. {
  1142. # return true if arg is one
  1143. (scalar @{$_[1]} == 1) && ($_[1]->[0] == 1) <=> 0;
  1144. }
  1145. sub _is_two
  1146. {
  1147. # return true if arg is two
  1148. (scalar @{$_[1]} == 1) && ($_[1]->[0] == 2) <=> 0;
  1149. }
  1150. sub _is_ten
  1151. {
  1152. # return true if arg is ten
  1153. (scalar @{$_[1]} == 1) && ($_[1]->[0] == 10) <=> 0;
  1154. }
  1155. sub __strip_zeros
  1156. {
  1157. # internal normalization function that strips leading zeros from the array
  1158. # args: ref to array
  1159. my $s = shift;
  1160. my $cnt = scalar @$s; # get count of parts
  1161. my $i = $cnt-1;
  1162. push @$s,0 if $i < 0; # div might return empty results, so fix it
  1163. return $s if @$s == 1; # early out
  1164. #print "strip: cnt $cnt i $i\n";
  1165. # '0', '3', '4', '0', '0',
  1166. # 0 1 2 3 4
  1167. # cnt = 5, i = 4
  1168. # i = 4
  1169. # i = 3
  1170. # => fcnt = cnt - i (5-2 => 3, cnt => 5-1 = 4, throw away from 4th pos)
  1171. # >= 1: skip first part (this can be zero)
  1172. while ($i > 0) { last if $s->[$i] != 0; $i--; }
  1173. $i++; splice @$s,$i if ($i < $cnt); # $i cant be 0
  1174. $s;
  1175. }
  1176. ###############################################################################
  1177. # check routine to test internal state for corruptions
  1178. sub _check
  1179. {
  1180. # used by the test suite
  1181. my $x = $_[1];
  1182. return "$x is not a reference" if !ref($x);
  1183. # are all parts are valid?
  1184. my $i = 0; my $j = scalar @$x; my ($e,$try);
  1185. while ($i < $j)
  1186. {
  1187. $e = $x->[$i]; $e = 'undef' unless defined $e;
  1188. $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e)";
  1189. last if $e !~ /^[+]?[0-9]+$/;
  1190. $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e) (stringify)";
  1191. last if "$e" !~ /^[+]?[0-9]+$/;
  1192. $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e) (cat-stringify)";
  1193. last if '' . "$e" !~ /^[+]?[0-9]+$/;
  1194. $try = ' < 0 || >= $BASE; '."($x, $e)";
  1195. last if $e <0 || $e >= $BASE;
  1196. # this test is disabled, since new/bnorm and certain ops (like early out
  1197. # in add/sub) are allowed/expected to leave '00000' in some elements
  1198. #$try = '=~ /^00+/; '."($x, $e)";
  1199. #last if $e =~ /^00+/;
  1200. $i++;
  1201. }
  1202. return "Illegal part '$e' at pos $i (tested: $try)" if $i < $j;
  1203. 0;
  1204. }
  1205. ###############################################################################
  1206. sub _mod
  1207. {
  1208. # if possible, use mod shortcut
  1209. my ($c,$x,$yo) = @_;
  1210. # slow way since $y to big
  1211. if (scalar @$yo > 1)
  1212. {
  1213. my ($xo,$rem) = _div($c,$x,$yo);
  1214. return $rem;
  1215. }
  1216. my $y = $yo->[0];
  1217. # both are single element arrays
  1218. if (scalar @$x == 1)
  1219. {
  1220. $x->[0] %= $y;
  1221. return $x;
  1222. }
  1223. # @y is a single element, but @x has more than one element
  1224. my $b = $BASE % $y;
  1225. if ($b == 0)
  1226. {
  1227. # when BASE % Y == 0 then (B * BASE) % Y == 0
  1228. # (B * BASE) % $y + A % Y => A % Y
  1229. # so need to consider only last element: O(1)
  1230. $x->[0] %= $y;
  1231. }
  1232. elsif ($b == 1)
  1233. {
  1234. # else need to go through all elements: O(N), but loop is a bit simplified
  1235. my $r = 0;
  1236. foreach (@$x)
  1237. {
  1238. $r = ($r + $_) % $y; # not much faster, but heh...
  1239. #$r += $_ % $y; $r %= $y;
  1240. }
  1241. $r = 0 if $r == $y;
  1242. $x->[0] = $r;
  1243. }
  1244. else
  1245. {
  1246. # else need to go through all elements: O(N)
  1247. my $r = 0; my $bm = 1;
  1248. foreach (@$x)
  1249. {
  1250. $r = ($_ * $bm + $r) % $y;
  1251. $bm = ($bm * $b) % $y;
  1252. #$r += ($_ % $y) * $bm;
  1253. #$bm *= $b;
  1254. #$bm %= $y;
  1255. #$r %= $y;
  1256. }
  1257. $r = 0 if $r == $y;
  1258. $x->[0] = $r;
  1259. }
  1260. splice (@$x,1); # keep one element of $x
  1261. $x;
  1262. }
  1263. ##############################################################################
  1264. # shifts
  1265. sub _rsft
  1266. {
  1267. my ($c,$x,$y,$n) = @_;
  1268. if ($n != 10)
  1269. {
  1270. $n = _new($c,$n); return _div($c,$x, _pow($c,$n,$y));
  1271. }
  1272. # shortcut (faster) for shifting by 10)
  1273. # multiples of $BASE_LEN
  1274. my $dst = 0; # destination
  1275. my $src = _num($c,$y); # as normal int
  1276. my $xlen = (@$x-1)*$BASE_LEN+length(int($x->[-1])); # len of x in digits
  1277. if ($src >= $xlen or ($src == $xlen and ! defined $x->[1]))
  1278. {
  1279. # 12345 67890 shifted right by more than 10 digits => 0
  1280. splice (@$x,1); # leave only one element
  1281. $x->[0] = 0; # set to zero
  1282. return $x;
  1283. }
  1284. my $rem = $src % $BASE_LEN; # remainder to shift
  1285. $src = int($src / $BASE_LEN); # source
  1286. if ($rem == 0)
  1287. {
  1288. splice (@$x,0,$src); # even faster, 38.4 => 39.3
  1289. }
  1290. else
  1291. {
  1292. my $len = scalar @$x - $src; # elems to go
  1293. my $vd; my $z = '0'x $BASE_LEN;
  1294. $x->[scalar @$x] = 0; # avoid || 0 test inside loop
  1295. while ($dst < $len)
  1296. {
  1297. $vd = $z.$x->[$src];
  1298. $vd = substr($vd,-$BASE_LEN,$BASE_LEN-$rem);
  1299. $src++;
  1300. $vd = substr($z.$x->[$src],-$rem,$rem) . $vd;
  1301. $vd = substr($vd,-$BASE_LEN,$BASE_LEN) if length($vd) > $BASE_LEN;
  1302. $x->[$dst] = int($vd);
  1303. $dst++;
  1304. }
  1305. splice (@$x,$dst) if $dst > 0; # kill left-over array elems
  1306. pop @$x if $x->[-1] == 0 && @$x > 1; # kill last element if 0
  1307. } # else rem == 0
  1308. $x;
  1309. }
  1310. sub _lsft
  1311. {
  1312. my ($c,$x,$y,$n) = @_;
  1313. if ($n != 10)
  1314. {
  1315. $n = _new($c,$n); return _mul($c,$x, _pow($c,$n,$y));
  1316. }
  1317. # shortcut (faster) for shifting by 10) since we are in base 10eX
  1318. # multiples of $BASE_LEN:
  1319. my $src = scalar @$x; # source
  1320. my $len = _num($c,$y); # shift-len as normal int
  1321. my $rem = $len % $BASE_LEN; # remainder to shift
  1322. my $dst = $src + int($len/$BASE_LEN); # destination
  1323. my $vd; # further speedup
  1324. $x->[$src] = 0; # avoid first ||0 for speed
  1325. my $z = '0' x $BASE_LEN;
  1326. while ($src >= 0)
  1327. {
  1328. $vd = $x->[$src]; $vd = $z.$vd;
  1329. $vd = substr($vd,-$BASE_LEN+$rem,$BASE_LEN-$rem);
  1330. $vd .= $src > 0 ? substr($z.$x->[$src-1],-$BASE_LEN,$rem) : '0' x $rem;
  1331. $vd = substr($vd,-$BASE_LEN,$BASE_LEN) if length($vd) > $BASE_LEN;
  1332. $x->[$dst] = int($vd);
  1333. $dst--; $src--;
  1334. }
  1335. # set lowest parts to 0
  1336. while ($dst >= 0) { $x->[$dst--] = 0; }
  1337. # fix spurios last zero element
  1338. splice @$x,-1 if $x->[-1] == 0;
  1339. $x;
  1340. }
  1341. sub _pow
  1342. {
  1343. # power of $x to $y
  1344. # ref to array, ref to array, return ref to array
  1345. my ($c,$cx,$cy) = @_;
  1346. if (scalar @$cy == 1 && $cy->[0] == 0)
  1347. {
  1348. splice (@$cx,1); $cx->[0] = 1; # y == 0 => x => 1
  1349. return $cx;
  1350. }
  1351. if ((scalar @$cx == 1 && $cx->[0] == 1) || # x == 1
  1352. (scalar @$cy == 1 && $cy->[0] == 1)) # or y == 1
  1353. {
  1354. return $cx;
  1355. }
  1356. if (scalar @$cx == 1 && $cx->[0] == 0)
  1357. {
  1358. splice (@$cx,1); $cx->[0] = 0; # 0 ** y => 0 (if not y <= 0)
  1359. return $cx;
  1360. }
  1361. my $pow2 = _one();
  1362. my $y_bin = _as_bin($c,$cy); $y_bin =~ s/^0b//;
  1363. my $len = length($y_bin);
  1364. while (--$len > 0)
  1365. {
  1366. _mul($c,$pow2,$cx) if substr($y_bin,$len,1) eq '1'; # is odd?
  1367. _mul($c,$cx,$cx);
  1368. }
  1369. _mul($c,$cx,$pow2);
  1370. $cx;
  1371. }
  1372. sub _nok
  1373. {
  1374. # n over k
  1375. # ref to array, return ref to array
  1376. my ($c,$n,$k) = @_;
  1377. # ( 7 ) 7! 1*2*3*4 * 5*6*7 5 * 6 * 7 6 7
  1378. # ( - ) = --------- = --------------- = --------- = 5 * - * -
  1379. # ( 3 ) (7-3)! 3! 1*2*3*4 * 1*2*3 1 * 2 * 3 2 3
  1380. if (!_is_zero($c,$k))
  1381. {
  1382. my $x = _copy($c,$n);
  1383. _sub($c,$n,$k);
  1384. _inc($c,$n);
  1385. my $f = _copy($c,$n); _inc($c,$f); # n = 5, f = 6, d = 2
  1386. my $d = _two($c);
  1387. while (_acmp($c,$f,$x) <= 0) # f <= n ?
  1388. {
  1389. # n = (n * f / d) == 5 * 6 / 2
  1390. $n = _mul($c,$n,$f); $n = _div($c,$n,$d);
  1391. # f = 7, d = 3
  1392. _inc($c,$f); _inc($c,$d);
  1393. }
  1394. }
  1395. else
  1396. {
  1397. # keep ref to $n and set it to 1
  1398. splice (@$n,1); $n->[0] = 1;
  1399. }
  1400. $n;
  1401. }
  1402. my @factorials = (
  1403. 1,
  1404. 1,
  1405. 2,
  1406. 2*3,
  1407. 2*3*4,
  1408. 2*3*4*5,
  1409. 2*3*4*5*6,
  1410. 2*3*4*5*6*7,
  1411. );
  1412. sub _fac
  1413. {
  1414. # factorial of $x
  1415. # ref to array, return ref to array
  1416. my ($c,$cx) = @_;
  1417. if ((@$cx == 1) && ($cx->[0] <= 7))
  1418. {
  1419. $cx->[0] = $factorials[$cx->[0]]; # 0 => 1, 1 => 1, 2 => 2 etc.
  1420. return $cx;
  1421. }
  1422. if ((@$cx == 1) && # we do this only if $x >= 12 and $x <= 7000
  1423. ($cx->[0] >= 12 && $cx->[0] < 7000))
  1424. {
  1425. # Calculate (k-j) * (k-j+1) ... k .. (k+j-1) * (k + j)
  1426. # See http://blogten.blogspot.com/2007/01/calculating-n.html
  1427. # The above series can be expressed as factors:
  1428. # k * k - (j - i) * 2
  1429. # We cache k*k, and calculate (j * j) as the sum of the first j odd integers
  1430. # This will not work when N exceeds the storage of a Perl scalar, however,
  1431. # in this case the algorithm would be way to slow to terminate, anyway.
  1432. # As soon as the last element of $cx is 0, we split it up and remember
  1433. # how many zeors we got so far. The reason is that n! will accumulate
  1434. # zeros at the end rather fast.
  1435. my $zero_elements = 0;
  1436. # If n is even, set n = n -1
  1437. my $k = _num($c,$cx); my $even = 1;
  1438. if (($k & 1) == 0)
  1439. {
  1440. $even = $k; $k --;
  1441. }
  1442. # set k to the center point
  1443. $k = ($k + 1) / 2;
  1444. # print "k $k even: $even\n";
  1445. # now calculate k * k
  1446. my $k2 = $k * $k;
  1447. my $odd = 1; my $sum = 1;
  1448. my $i = $k - 1;
  1449. # keep reference to x
  1450. my $new_x = _new($c, $k * $even);
  1451. @$cx = @$new_x;
  1452. if ($cx->[0] == 0)
  1453. {
  1454. $zero_elements ++; shift @$cx;
  1455. }
  1456. # print STDERR "x = ", _str($c,$cx),"\n";
  1457. my $BASE2 = int(sqrt($BASE))-1;
  1458. my $j = 1;
  1459. while ($j <= $i)
  1460. {
  1461. my $m = ($k2 - $sum); $odd += 2; $sum += $odd; $j++;
  1462. while ($j <= $i && ($m < $BASE2) && (($k2 - $sum) < $BASE2))
  1463. {
  1464. $m *= ($k2 - $sum);
  1465. $odd += 2; $sum += $odd; $j++;
  1466. # print STDERR "\n k2 $k2 m $m sum $sum odd $odd\n"; sleep(1);
  1467. }
  1468. if ($m < $BASE)
  1469. {
  1470. _mul($c,$cx,[$m]);
  1471. }
  1472. else
  1473. {
  1474. _mul($c,$cx,$c->_new($m));
  1475. }
  1476. if ($cx->[0] == 0)
  1477. {
  1478. $zero_elements ++; shift @$cx;
  1479. }
  1480. # print STDERR "Calculate $k2 - $sum = $m (x = ", _str($c,$cx),")\n";
  1481. }
  1482. # multiply in the zeros again
  1483. unshift @$cx, (0) x $zero_elements;
  1484. return $cx;
  1485. }
  1486. # go forward until $base is exceeded
  1487. # limit is either $x steps (steps == 100 means a result always too high) or
  1488. # $base.
  1489. my $steps = 100; $steps = $cx->[0] if @$cx == 1;
  1490. my $r = 2; my $cf = 3; my $step = 2; my $last = $r;
  1491. while ($r*$cf < $BASE && $step < $steps)
  1492. {
  1493. $last = $r; $r *= $cf++; $step++;
  1494. }
  1495. if ((@$cx == 1) && $step == $cx->[0])
  1496. {
  1497. # completely done, so keep reference to $x and return
  1498. $cx->[0] = $r;
  1499. return $cx;
  1500. }
  1501. # now we must do the left over steps
  1502. my $n; # steps still to do
  1503. if (scalar @$cx == 1)
  1504. {
  1505. $n = $cx->[0];
  1506. }
  1507. else
  1508. {
  1509. $n = _copy($c,$cx);
  1510. }
  1511. # Set $cx to the last result below $BASE (but keep ref to $x)
  1512. $cx->[0] = $last; splice (@$cx,1);
  1513. # As soon as the last element of $cx is 0, we split it up and remember
  1514. # how many zeors we got so far. The reason is that n! will accumulate
  1515. # zeros at the end rather fast.
  1516. my $zero_elements = 0;
  1517. # do left-over steps fit into a scalar?
  1518. if (ref $n eq 'ARRAY')
  1519. {
  1520. # No, so use slower inc() & cmp()
  1521. # ($n is at least $BASE here)
  1522. my $base_2 = int(sqrt($BASE)) - 1;
  1523. #print STDERR "base_2: $base_2\n";
  1524. while ($step < $base_2)
  1525. {
  1526. if ($cx->[0] == 0)
  1527. {
  1528. $zero_elements ++; shift @$cx;
  1529. }
  1530. my $b = $step * ($step + 1); $step += 2;
  1531. _mul($c,$cx,[$b]);
  1532. }
  1533. $step = [$step];
  1534. while (_acmp($c,$step,$n) <= 0)
  1535. {
  1536. if ($cx->[0] == 0)
  1537. {
  1538. $zero_elements ++; shift @$cx;
  1539. }
  1540. _mul($c,$cx,$step); _inc($c,$step);
  1541. }
  1542. }
  1543. else
  1544. {
  1545. # Yes, so we can speed it up slightly
  1546. # print "# left over steps $n\n";
  1547. my $base_4 = int(sqrt(sqrt($BASE))) - 2;
  1548. #print STDERR "base_4: $base_4\n";
  1549. my $n4 = $n - 4;
  1550. while ($step < $n4 && $step < $base_4)
  1551. {
  1552. if ($cx->[0] == 0)
  1553. {
  1554. $zero_elements ++; shift @$cx;
  1555. }
  1556. my $b = $step * ($step + 1); $step += 2; $b *= $step * ($step + 1); $step += 2;
  1557. _mul($c,$cx,[$b]);
  1558. }
  1559. my $base_2 = int(sqrt($BASE)) - 1;
  1560. my $n2 = $n - 2;
  1561. #print STDERR "base_2: $base_2\n";
  1562. while ($step < $n2 && $step < $base_2)
  1563. {
  1564. if ($cx->[0] == 0)
  1565. {
  1566. $zero_elements ++; shift @$cx;
  1567. }
  1568. my $b = $step * ($step + 1); $step += 2;
  1569. _mul($c,$cx,[$b]);
  1570. }
  1571. # do what's left over
  1572. while ($step <= $n)
  1573. {
  1574. _mul($c,$cx,[$step]); $step++;
  1575. if ($cx->[0] == 0)
  1576. {
  1577. $zero_elements ++; shift @$cx;
  1578. }
  1579. }
  1580. }
  1581. # multiply in the zeros again
  1582. unshift @$cx, (0) x $zero_elements;
  1583. $cx; # return result
  1584. }
  1585. #############################################################################
  1586. sub _log_int
  1587. {
  1588. # calculate integer log of $x to base $base
  1589. # ref to array, ref to array - return ref to array
  1590. my ($c,$x,$base) = @_;
  1591. # X == 0 => NaN
  1592. return if (scalar @$x == 1 && $x->[0] == 0);
  1593. # BASE 0 or 1 => NaN
  1594. return if (scalar @$base == 1 && $base->[0] < 2);
  1595. my $cmp = _acmp($c,$x,$base); # X == BASE => 1
  1596. if ($cmp == 0)
  1597. {
  1598. splice (@$x,1); $x->[0] = 1;
  1599. return ($x,1)
  1600. }
  1601. # X < BASE
  1602. if ($cmp < 0)
  1603. {
  1604. splice (@$x,1); $x->[0] = 0;
  1605. return ($x,undef);
  1606. }
  1607. my $x_org = _copy($c,$x); # preserve x
  1608. splice(@$x,1); $x->[0] = 1; # keep ref to $x
  1609. # Compute a guess for the result based on:
  1610. # $guess = int ( length_in_base_10(X) / ( log(base) / log(10) ) )
  1611. my $len = _len($c,$x_org);
  1612. my $log = log($base->[-1]) / log(10);
  1613. # for each additional element in $base, we add $BASE_LEN to the result,
  1614. # based on the observation that log($BASE,10) is BASE_LEN and
  1615. # log(x*y) == log(x) + log(y):
  1616. $log += ((scalar @$base)-1) * $BASE_LEN;
  1617. # calculate now a guess based on the values obtained above:
  1618. my $res = int($len / $log);
  1619. $x->[0] = $res;
  1620. my $trial = _pow ($c, _copy($c, $base), $x);
  1621. my $a = _acmp($c,$trial,$x_org);
  1622. # print STDERR "# trial ", _str($c,$x)," was: $a (0 = exact, -1 too small, +1 too big)\n";
  1623. # found an exact result?
  1624. return ($x,1) if $a == 0;
  1625. if ($a > 0)
  1626. {
  1627. # or too big
  1628. _div($c,$trial,$base); _dec($c, $x);
  1629. while (($a = _acmp($c,$trial,$x_org)) > 0)
  1630. {
  1631. # print STDERR "# big _log_int at ", _str($c,$x), "\n";
  1632. _div($c,$trial,$base); _dec($c, $x);
  1633. }
  1634. # result is now exact (a == 0), or too small (a < 0)
  1635. return ($x, $a == 0 ? 1 : 0);
  1636. }
  1637. # else: result was to small
  1638. _mul($c,$trial,$base);
  1639. # did we now get the right