File Coverage

blib/lib/Math/BigInt/Lib.pm
Criterion Covered Total %
statement 227 1008 22.5
branch 93 446 20.8
condition 9 42 21.4
subroutine 21 104 20.1
pod n/a
total 350 1600 21.8


line stmt bran cond sub pod time code
1             package Math::BigInt::Lib;
2              
3 50     50   840 use 5.006001;
  50         178  
4 50     50   244 use strict;
  50         110  
  50         1278  
5 50     50   251 use warnings;
  50         133  
  50         4642  
6              
7             our $VERSION = '2.005003';
8             $VERSION =~ tr/_//d;
9              
10 50     50   292 use Carp;
  50         117  
  50         104840  
11              
12             use overload
13              
14             # overload key: with_assign
15              
16             '+' => sub {
17 0     0   0 my $class = ref $_[0];
18 0         0 my $x = $class -> _copy($_[0]);
19 0 0       0 my $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
20 0         0 return $class -> _add($x, $y);
21             },
22              
23             '-' => sub {
24 0     0   0 my $class = ref $_[0];
25 0         0 my ($x, $y);
26 0 0       0 if ($_[2]) { # if swapped
27 0         0 $y = $_[0];
28 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
29             } else {
30 0         0 $x = $class -> _copy($_[0]);
31 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
32             }
33 0         0 return $class -> _sub($x, $y);
34             },
35              
36             '*' => sub {
37 0     0   0 my $class = ref $_[0];
38 0         0 my $x = $class -> _copy($_[0]);
39 0 0       0 my $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
40 0         0 return $class -> _mul($x, $y);
41             },
42              
43             '/' => sub {
44 0     0   0 my $class = ref $_[0];
45 0         0 my ($x, $y);
46 0 0       0 if ($_[2]) { # if swapped
47 0         0 $y = $_[0];
48 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
49             } else {
50 0         0 $x = $class -> _copy($_[0]);
51 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
52             }
53 0         0 return $class -> _div($x, $y);
54             },
55              
56             '%' => sub {
57 0     0   0 my $class = ref $_[0];
58 0         0 my ($x, $y);
59 0 0       0 if ($_[2]) { # if swapped
60 0         0 $y = $_[0];
61 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
62             } else {
63 0         0 $x = $class -> _copy($_[0]);
64 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
65             }
66 0         0 return $class -> _mod($x, $y);
67             },
68              
69             '**' => sub {
70 0     0   0 my $class = ref $_[0];
71 0         0 my ($x, $y);
72 0 0       0 if ($_[2]) { # if swapped
73 0         0 $y = $_[0];
74 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
75             } else {
76 0         0 $x = $class -> _copy($_[0]);
77 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
78             }
79 0         0 return $class -> _pow($x, $y);
80             },
81              
82             '<<' => sub {
83 0     0   0 my $class = ref $_[0];
84 0         0 my ($x, $y);
85 0 0       0 if ($_[2]) { # if swapped
86 0         0 $y = $class -> _num($_[0]);
87 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
88             } else {
89 0         0 $x = $_[0];
90 0 0       0 $y = ref($_[1]) ? $class -> _num($_[1]) : $_[1];
91             }
92 0         0 return $class -> _lsft($x, $y);
93             },
94              
95             '>>' => sub {
96 0     0   0 my $class = ref $_[0];
97 0         0 my ($x, $y);
98 0 0       0 if ($_[2]) { # if swapped
99 0         0 $y = $_[0];
100 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
101             } else {
102 0         0 $x = $class -> _copy($_[0]);
103 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
104             }
105 0         0 return $class -> _rsft($x, $y);
106             },
107              
108             # overload key: num_comparison
109              
110             '<' => sub {
111 0     0   0 my $class = ref $_[0];
112 0         0 my ($x, $y);
113 0 0       0 if ($_[2]) { # if swapped
114 0         0 $y = $_[0];
115 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
116             } else {
117 0         0 $x = $class -> _copy($_[0]);
118 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
119             }
120 0         0 return $class -> _acmp($x, $y) < 0;
121             },
122              
123             '<=' => sub {
124 0     0   0 my $class = ref $_[0];
125 0         0 my ($x, $y);
126 0 0       0 if ($_[2]) { # if swapped
127 0         0 $y = $_[0];
128 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
129             } else {
130 0         0 $x = $class -> _copy($_[0]);
131 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
132             }
133 0         0 return $class -> _acmp($x, $y) <= 0;
134             },
135              
136             '>' => sub {
137 0     0   0 my $class = ref $_[0];
138 0         0 my ($x, $y);
139 0 0       0 if ($_[2]) { # if swapped
140 0         0 $y = $_[0];
141 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
142             } else {
143 0         0 $x = $class -> _copy($_[0]);
144 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
145             }
146 0         0 return $class -> _acmp($x, $y) > 0;
147             },
148              
149             '>=' => sub {
150 0     0   0 my $class = ref $_[0];
151 0         0 my ($x, $y);
152 0 0       0 if ($_[2]) { # if swapped
153 0         0 $y = $_[0];
154 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
155             } else {
156 0         0 $x = $class -> _copy($_[0]);
157 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
158             }
159 0         0 return $class -> _acmp($x, $y) >= 0;
160             },
161              
162             '==' => sub {
163 12678     12678   25215 my $class = ref $_[0];
164 12678         40374 my $x = $class -> _copy($_[0]);
165 12678 50       30458 my $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
166 12678         36682 return $class -> _acmp($x, $y) == 0;
167             },
168              
169             '!=' => sub {
170 0     0   0 my $class = ref $_[0];
171 0         0 my $x = $class -> _copy($_[0]);
172 0 0       0 my $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
173 0         0 return $class -> _acmp($x, $y) != 0;
174             },
175              
176             # overload key: 3way_comparison
177              
178             '<=>' => sub {
179 0     0   0 my $class = ref $_[0];
180 0         0 my ($x, $y);
181 0 0       0 if ($_[2]) { # if swapped
182 0         0 $y = $_[0];
183 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
184             } else {
185 0         0 $x = $class -> _copy($_[0]);
186 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
187             }
188 0         0 return $class -> _acmp($x, $y);
189             },
190              
191             # overload key: binary
192              
193             '&' => sub {
194 0     0   0 my $class = ref $_[0];
195 0         0 my ($x, $y);
196 0 0       0 if ($_[2]) { # if swapped
197 0         0 $y = $_[0];
198 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
199             } else {
200 0         0 $x = $class -> _copy($_[0]);
201 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
202             }
203 0         0 return $class -> _and($x, $y);
204             },
205              
206             '|' => sub {
207 0     0   0 my $class = ref $_[0];
208 0         0 my ($x, $y);
209 0 0       0 if ($_[2]) { # if swapped
210 0         0 $y = $_[0];
211 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
212             } else {
213 0         0 $x = $class -> _copy($_[0]);
214 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
215             }
216 0         0 return $class -> _or($x, $y);
217             },
218              
219             '^' => sub {
220 0     0   0 my $class = ref $_[0];
221 0         0 my ($x, $y);
222 0 0       0 if ($_[2]) { # if swapped
223 0         0 $y = $_[0];
224 0 0       0 $x = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
225             } else {
226 0         0 $x = $class -> _copy($_[0]);
227 0 0       0 $y = ref($_[1]) ? $_[1] : $class -> _new($_[1]);
228             }
229 0         0 return $class -> _xor($x, $y);
230             },
231              
232             # overload key: func
233              
234 0     0   0 'abs' => sub { $_[0] },
235              
236             'sqrt' => sub {
237 0     0   0 my $class = ref $_[0];
238 0         0 return $class -> _sqrt($class -> _copy($_[0]));
239             },
240              
241 0     0   0 'int' => sub { $_[0] },
242              
243             # overload key: conversion
244              
245 0 0   0   0 'bool' => sub { ref($_[0]) -> _is_zero($_[0]) ? '' : 1; },
246              
247 4     4   24 '""' => sub { ref($_[0]) -> _str($_[0]); },
248              
249 0     0   0 '0+' => sub { ref($_[0]) -> _num($_[0]); },
250              
251 0     0   0 '=' => sub { ref($_[0]) -> _copy($_[0]); },
252              
253 50     50   1820 ;
  50         3707  
  50         3175  
254              
255             sub _new {
256 0     0   0 croak "@{[(caller 0)[3]]} method not implemented";
  0         0  
257             }
258              
259             sub _zero {
260 0     0   0 my $class = shift;
261 0         0 return $class -> _new("0");
262             }
263              
264             sub _one {
265 0     0   0 my $class = shift;
266 0         0 return $class -> _new("1");
267             }
268              
269             sub _two {
270 0     0   0 my $class = shift;
271 0         0 return $class -> _new("2");
272              
273             }
274             sub _ten {
275 0     0   0 my $class = shift;
276 0         0 return $class -> _new("10");
277             }
278              
279             sub _1ex {
280 0     0   0 my ($class, $exp) = @_;
281 0 0       0 $exp = $class -> _num($exp) if ref($exp);
282 0         0 return $class -> _new("1" . ("0" x $exp));
283             }
284              
285             sub _copy {
286 0     0   0 my ($class, $x) = @_;
287 0         0 return $class -> _new($class -> _str($x));
288             }
289              
290             # catch and throw away
291       50     sub import { }
292              
293             ##############################################################################
294             # convert back to string and number
295              
296             sub _str {
297             # Convert number from internal base 1eN format to string format. Internal
298             # format is always normalized, i.e., no leading zeros.
299 0     0   0 croak "@{[(caller 0)[3]]} method not implemented";
  0         0  
300             }
301              
302             sub _num {
303 0     0   0 my ($class, $x) = @_;
304 0         0 0 + $class -> _str($x);
305             }
306              
307             ##############################################################################
308             # actual math code
309              
310             sub _add {
311 0     0   0 croak "@{[(caller 0)[3]]} method not implemented";
  0         0  
312             }
313              
314             sub _sub {
315 0     0   0 croak "@{[(caller 0)[3]]} method not implemented";
  0         0  
316             }
317              
318             sub _mul {
319 0     0   0 my ($class, $x, $y) = @_;
320 0         0 my $sum = $class -> _zero();
321 0         0 my $i = $class -> _zero();
322 0         0 while ($class -> _acmp($i, $y) < 0) {
323 0         0 $sum = $class -> _add($sum, $x);
324 0         0 $i = $class -> _inc($i);
325             }
326 0         0 return $sum;
327             }
328              
329             sub _div {
330 0     0   0 my ($class, $x, $y) = @_;
331              
332 0 0       0 croak "@{[(caller 0)[3]]} requires non-zero divisor"
  0         0  
333             if $class -> _is_zero($y);
334              
335 0         0 my $r = $class -> _copy($x);
336 0         0 my $q = $class -> _zero();
337 0         0 while ($class -> _acmp($r, $y) >= 0) {
338 0         0 $q = $class -> _inc($q);
339 0         0 $r = $class -> _sub($r, $y);
340             }
341              
342 0 0       0 return $q, $r if wantarray;
343 0         0 return $q;
344             }
345              
346             sub _inc {
347 0     0   0 my ($class, $x) = @_;
348 0         0 $class -> _add($x, $class -> _one());
349             }
350              
351             sub _dec {
352 0     0   0 my ($class, $x) = @_;
353 0         0 $class -> _sub($x, $class -> _one());
354             }
355              
356             # Signed addition. If the flag is false, $xa might be modified, but not $ya. If
357             # the false is true, $ya might be modified, but not $xa.
358              
359             sub _sadd {
360 71794     71794   117731 my $class = shift;
361 71794         169904 my ($xa, $xs, $ya, $ys, $flag) = @_;
362 71794         115802 my ($za, $zs);
363              
364             # If the signs are equal we can add them (-5 + -3 => -(5 + 3) => -8)
365              
366 71794 100       167511 if ($xs eq $ys) {
367 39546 50       76182 if ($flag) {
368 0         0 $za = $class -> _add($ya, $xa);
369             } else {
370 39546         119578 $za = $class -> _add($xa, $ya);
371             }
372 39546 100       117359 $zs = $class -> _is_zero($za) ? '+' : $xs;
373 39546         182207 return $za, $zs;
374             }
375              
376 32248         102020 my $acmp = $class -> _acmp($xa, $ya); # abs(x) = abs(y)
377              
378 32248 100       79690 if ($acmp == 0) { # x = -y or -x = y
379 7379         24841 $za = $class -> _zero();
380 7379         13701 $zs = '+';
381 7379         33817 return $za, $zs;
382             }
383              
384 24869 100       52987 if ($acmp > 0) { # abs(x) > abs(y)
385 17493         55145 $za = $class -> _sub($xa, $ya, $flag);
386 17493         33829 $zs = $xs;
387             } else { # abs(x) < abs(y)
388 7376         24090 $za = $class -> _sub($ya, $xa, !$flag);
389 7376         14014 $zs = $ys;
390             }
391 24869         112739 return $za, $zs;
392             }
393              
394             # Signed subtraction. If the flag is false, $xa might be modified, but not $ya.
395             # If the false is true, $ya might be modified, but not $xa.
396              
397             sub _ssub {
398 38192     38192   65414 my $class = shift;
399 38192         99274 my ($xa, $xs, $ya, $ys, $flag) = @_;
400              
401             # Swap sign of second operand and let _sadd() do the job.
402 38192 100       92420 $ys = $ys eq '+' ? '-' : '+';
403 38192         101769 $class -> _sadd($xa, $xs, $ya, $ys, $flag);
404             }
405              
406             ##############################################################################
407             # testing
408              
409             sub _acmp {
410             # Compare two (absolute) values. Return -1, 0, or 1.
411 0     0   0 my ($class, $x, $y) = @_;
412 0         0 my $xstr = $class -> _str($x);
413 0         0 my $ystr = $class -> _str($y);
414              
415 0 0       0 length($xstr) <=> length($ystr) || $xstr cmp $ystr;
416             }
417              
418             sub _scmp {
419             # Compare two signed values. Return -1, 0, or 1.
420 513     513   1538 my ($class, $xa, $xs, $ya, $ys) = @_;
421 513 100       1330 if ($xs eq '+') {
422 430 100       882 if ($ys eq '+') {
423 410         1294 return $class -> _acmp($xa, $ya);
424             } else {
425 20         63 return 1;
426             }
427             } else {
428 83 100       271 if ($ys eq '+') {
429 35         109 return -1;
430             } else {
431 48         156 return $class -> _acmp($ya, $xa);
432             }
433             }
434             }
435              
436             sub _len {
437 0     0   0 my ($class, $x) = @_;
438 0         0 CORE::length($class -> _str($x));
439             }
440              
441             sub _alen {
442 27     27   170 my ($class, $x) = @_;
443 27         128 $class -> _len($x);
444             }
445              
446             sub _digit {
447 0     0   0 my ($class, $x, $n) = @_;
448 0         0 substr($class ->_str($x), -($n+1), 1);
449             }
450              
451             sub _digitsum {
452 0     0   0 my ($class, $x) = @_;
453              
454 0         0 my $len = $class -> _len($x);
455 0         0 my $sum = $class -> _zero();
456 0         0 for (my $i = 0 ; $i < $len ; ++$i) {
457 0         0 my $digit = $class -> _digit($x, $i);
458 0         0 $digit = $class -> _new($digit);
459 0         0 $sum = $class -> _add($sum, $digit);
460             }
461              
462 0         0 return $sum;
463             }
464              
465             sub _zeros {
466 0     0   0 my ($class, $x) = @_;
467 0         0 my $str = $class -> _str($x);
468 0 0       0 $str =~ /[^0](0*)\z/ ? CORE::length($1) : 0;
469             }
470              
471             ##############################################################################
472             # _is_* routines
473              
474             sub _is_zero {
475             # return true if arg is zero
476 0     0   0 my ($class, $x) = @_;
477 0         0 $class -> _str($x) == 0;
478             }
479              
480             sub _is_even {
481             # return true if arg is even
482 0     0   0 my ($class, $x) = @_;
483 0         0 substr($class -> _str($x), -1, 1) % 2 == 0;
484             }
485              
486             sub _is_odd {
487             # return true if arg is odd
488 0     0   0 my ($class, $x) = @_;
489 0         0 substr($class -> _str($x), -1, 1) % 2 != 0;
490             }
491              
492             sub _is_one {
493             # return true if arg is one
494 0     0   0 my ($class, $x) = @_;
495 0         0 $class -> _str($x) == 1;
496             }
497              
498             sub _is_two {
499             # return true if arg is two
500 0     0   0 my ($class, $x) = @_;
501 0         0 $class -> _str($x) == 2;
502             }
503              
504             sub _is_ten {
505             # return true if arg is ten
506 0     0   0 my ($class, $x) = @_;
507 0         0 $class -> _str($x) == 10;
508             }
509              
510             ###############################################################################
511             # check routine to test internal state for corruptions
512              
513             sub _check {
514             # used by the test suite
515 8106     8106   18527 my ($class, $x) = @_;
516 8106 50       22625 return "Input is undefined" unless defined $x;
517 8106 100       19611 return "$x is not a reference" unless ref($x);
518 8105         21004 return 0;
519             }
520              
521             ###############################################################################
522              
523             sub _mod {
524             # modulus
525 0     0   0 my ($class, $x, $y) = @_;
526              
527 0 0       0 croak "@{[(caller 0)[3]]} requires non-zero second operand"
  0         0  
528             if $class -> _is_zero($y);
529              
530 0 0       0 if ($class -> can('_div')) {
531 0         0 $x = $class -> _copy($x);
532 0         0 my ($q, $r) = $class -> _div($x, $y);
533 0         0 return $r;
534             } else {
535 0         0 my $r = $class -> _copy($x);
536 0         0 while ($class -> _acmp($r, $y) >= 0) {
537 0         0 $r = $class -> _sub($r, $y);
538             }
539 0         0 return $r;
540             }
541             }
542              
543             ##############################################################################
544             # shifts
545              
546             sub _rsft {
547 0     0   0 my ($class, $x, $n, $b) = @_;
548 0 0       0 $b = $class -> _new($b) unless ref $b;
549 0         0 return scalar $class -> _div($x, $class -> _pow($class -> _copy($b), $n));
550             }
551              
552             sub _lsft {
553 0     0   0 my ($class, $x, $n, $b) = @_;
554 0 0       0 $b = $class -> _new($b) unless ref $b;
555 0         0 return $class -> _mul($x, $class -> _pow($class -> _copy($b), $n));
556             }
557              
558             sub _pow {
559             # power of $x to $y
560 0     0   0 my ($class, $x, $y) = @_;
561              
562 0 0       0 if ($class -> _is_zero($y)) {
563 0         0 return $class -> _one(); # y == 0 => x => 1
564             }
565              
566 0 0 0     0 if (($class -> _is_one($x)) || # x == 1
567             ($class -> _is_one($y))) # or y == 1
568             {
569 0         0 return $x;
570             }
571              
572 0 0       0 if ($class -> _is_zero($x)) {
573 0         0 return $class -> _zero(); # 0 ** y => 0 (if not y <= 0)
574             }
575              
576 0         0 my $pow2 = $class -> _one();
577              
578 0         0 my $y_bin = $class -> _as_bin($y);
579 0         0 $y_bin =~ s/^0b//;
580 0         0 my $len = length($y_bin);
581              
582 0         0 while (--$len > 0) {
583 0 0       0 $pow2 = $class -> _mul($pow2, $x) if substr($y_bin, $len, 1) eq '1';
584 0         0 $x = $class -> _mul($x, $x);
585             }
586              
587 0         0 $x = $class -> _mul($x, $pow2);
588 0         0 return $x;
589             }
590              
591             sub _nok {
592             # Return binomial coefficient (n over k).
593 0     0   0 my ($class, $n, $k) = @_;
594              
595             # If k > n/2, or, equivalently, 2*k > n, compute nok(n, k) as
596             # nok(n, n-k), to minimize the number if iterations in the loop.
597              
598             {
599 0         0 my $twok = $class -> _mul($class -> _two(), $class -> _copy($k));
  0         0  
600 0 0       0 if ($class -> _acmp($twok, $n) > 0) {
601 0         0 $k = $class -> _sub($class -> _copy($n), $k);
602             }
603             }
604              
605             # Example:
606             #
607             # / 7 \ 7! 1*2*3*4 * 5*6*7 5 * 6 * 7
608             # | | = --------- = --------------- = --------- = ((5 * 6) / 2 * 7) / 3
609             # \ 3 / (7-3)! 3! 1*2*3*4 * 1*2*3 1 * 2 * 3
610             #
611             # Equivalently, _nok(11, 5) is computed as
612             #
613             # (((((((7 * 8) / 2) * 9) / 3) * 10) / 4) * 11) / 5
614              
615 0 0       0 if ($class -> _is_zero($k)) {
616 0         0 return $class -> _one();
617             }
618              
619             # Make a copy of the original n, in case the subclass modifies n in-place.
620              
621 0         0 my $n_orig = $class -> _copy($n);
622              
623             # n = 5, f = 6, d = 2 (cf. example above)
624              
625 0         0 $n = $class -> _sub($n, $k);
626 0         0 $n = $class -> _inc($n);
627              
628 0         0 my $f = $class -> _copy($n);
629 0         0 $f = $class -> _inc($f);
630              
631 0         0 my $d = $class -> _two();
632              
633             # while f <= n (the original n, that is) ...
634              
635 0         0 while ($class -> _acmp($f, $n_orig) <= 0) {
636 0         0 $n = $class -> _mul($n, $f);
637 0         0 $n = $class -> _div($n, $d);
638 0         0 $f = $class -> _inc($f);
639 0         0 $d = $class -> _inc($d);
640             }
641              
642 0         0 return $n;
643             }
644              
645             #sub _fac {
646             # # factorial
647             # my ($class, $x) = @_;
648             #
649             # my $two = $class -> _two();
650             #
651             # if ($class -> _acmp($x, $two) < 0) {
652             # return $class -> _one();
653             # }
654             #
655             # my $i = $class -> _copy($x);
656             # while ($class -> _acmp($i, $two) > 0) {
657             # $i = $class -> _dec($i);
658             # $x = $class -> _mul($x, $i);
659             # }
660             #
661             # return $x;
662             #}
663              
664             sub _fac {
665             # factorial
666 0     0   0 my ($class, $x) = @_;
667              
668             # This is an implementation of the split recursive algorithm. See
669             # http://www.luschny.de/math/factorial/csharp/FactorialSplit.cs.html
670              
671 0         0 my $p = $class -> _one();
672 0         0 my $r = $class -> _one();
673 0         0 my $two = $class -> _two();
674              
675 0         0 my ($log2n) = $class -> _log_int($class -> _copy($x), $two);
676 0         0 my $h = $class -> _zero();
677 0         0 my $shift = $class -> _zero();
678 0         0 my $k = $class -> _one();
679              
680 0         0 while ($class -> _acmp($h, $x)) {
681 0         0 $shift = $class -> _add($shift, $h);
682 0         0 $h = $class -> _rsft($class -> _copy($x), $log2n, $two);
683 0 0       0 $log2n = $class -> _dec($log2n) if !$class -> _is_zero($log2n);
684 0         0 my $high = $class -> _copy($h);
685 0 0       0 $high = $class -> _dec($high) if $class -> _is_even($h);
686 0         0 while ($class -> _acmp($k, $high)) {
687 0         0 $k = $class -> _add($k, $two);
688 0         0 $p = $class -> _mul($p, $k);
689             }
690 0         0 $r = $class -> _mul($r, $p);
691             }
692 0         0 return $class -> _lsft($r, $shift, $two);
693             }
694              
695             sub _dfac {
696             # double factorial
697 77     77   200 my ($class, $x) = @_;
698              
699 77         323 my $two = $class -> _two();
700              
701 77 50       273 if ($class -> _acmp($x, $two) < 0) {
702 0         0 return $class -> _one();
703             }
704              
705 77         283 my $i = $class -> _copy($x);
706 77         237 while ($class -> _acmp($i, $two) > 0) {
707 210         680 $i = $class -> _sub($i, $two);
708 210         684 $x = $class -> _mul($x, $i);
709             }
710              
711 77         370 return $x;
712             }
713              
714             sub _log_int {
715             # calculate integer log of $x to base $base
716             # calculate integer log of $x to base $base
717             # ref to array, ref to array - return ref to array
718 0     0   0 my ($class, $x, $base) = @_;
719              
720             # X == 0 => NaN
721 0 0       0 return if $class -> _is_zero($x);
722              
723 0 0       0 $base = $class -> _new(2) unless defined($base);
724 0 0       0 $base = $class -> _new($base) unless ref($base);
725              
726             # BASE 0 or 1 => NaN
727 0 0 0     0 return if $class -> _is_zero($base) || $class -> _is_one($base);
728              
729             # X == 1 => 0 (is exact)
730 0 0       0 if ($class -> _is_one($x)) {
731 0 0       0 return $class -> _zero(), 1 if wantarray;
732 0         0 return $class -> _zero();
733             }
734              
735 0         0 my $cmp = $class -> _acmp($x, $base);
736              
737             # X == BASE => 1 (is exact)
738 0 0       0 if ($cmp == 0) {
739 0 0       0 return $class -> _one(), 1 if wantarray;
740 0         0 return $class -> _one();
741             }
742              
743             # 1 < X < BASE => 0 (is truncated)
744 0 0       0 if ($cmp < 0) {
745 0 0       0 return $class -> _zero(), 0 if wantarray;
746 0         0 return $class -> _zero();
747             }
748              
749 0         0 my $y;
750              
751             # log(x) / log(b) = log(xm * 10^xe) / log(bm * 10^be)
752             # = (log(xm) + xe*(log(10))) / (log(bm) + be*log(10))
753              
754             {
755 0         0 my $x_str = $class -> _str($x);
  0         0  
756 0         0 my $b_str = $class -> _str($base);
757 0         0 my $xm = "." . $x_str;
758 0         0 my $bm = "." . $b_str;
759 0         0 my $xe = length($x_str);
760 0         0 my $be = length($b_str);
761 0         0 my $log10 = log(10);
762 0         0 my $guess = int((log($xm) + $xe * $log10) / (log($bm) + $be * $log10));
763 0         0 $y = $class -> _new($guess);
764             }
765              
766 0         0 my $trial = $class -> _pow($class -> _copy($base), $y);
767 0         0 my $acmp = $class -> _acmp($trial, $x);
768              
769             # Too small?
770              
771 0         0 while ($acmp < 0) {
772 0         0 $trial = $class -> _mul($trial, $base);
773 0         0 $y = $class -> _inc($y);
774 0         0 $acmp = $class -> _acmp($trial, $x);
775             }
776              
777             # Too big?
778              
779 0         0 while ($acmp > 0) {
780 0         0 $trial = $class -> _div($trial, $base);
781 0         0 $y = $class -> _dec($y);
782 0         0 $acmp = $class -> _acmp($trial, $x);
783             }
784              
785 0 0       0 return wantarray ? ($y, 1) : $y if $acmp == 0; # result is exact
    0          
786 0 0       0 return wantarray ? ($y, 0) : $y; # result is too small
787             }
788              
789             sub _ilog2 {
790 0     0   0 my ($class, $x) = @_;
791              
792 0 0       0 return if $class -> _is_zero($x);
793              
794 0         0 my $str = $class -> _to_hex($x);
795              
796             # First do the bits in all but the most significant hex digit.
797              
798 0         0 my $y = $class -> _new(length($str) - 1);
799 0         0 $y = $class -> _mul($y, $class -> _new(4));
800              
801             # Now add the number of bits in the most significant hex digit.
802              
803 0         0 my $n = int log(hex(substr($str, 0, 1))) / log(2);
804 0         0 $y = $class -> _add($y, $class -> _new($n));
805 0 0       0 return $y unless wantarray;
806              
807 0         0 my $pow2 = $class -> _lsft($class -> _one(), $y, 2);
808 0 0       0 my $is_exact = $class -> _acmp($x, $pow2) == 0 ? 1 : 0;
809 0         0 return $y, $is_exact;
810             }
811              
812             sub _ilog10 {
813 0     0   0 my ($class, $x) = @_;
814              
815 0 0       0 return if $class -> _is_zero($x);
816              
817 0         0 my $str = $class -> _str($x);
818 0         0 my $len = length($str);
819 0         0 my $y = $class -> _new($len - 1);
820 0 0       0 return $y unless wantarray;
821              
822             #my $pow10 = $class -> _1ex($y);
823             #my $is_exact = $class -> _acmp($x, $pow10) ? 1 : 0;
824              
825 0 0       0 my $is_exact = $str =~ /^10*$/ ? 1 : 0;
826 0         0 return $y, $is_exact;
827             }
828              
829             sub _clog2 {
830 0     0   0 my ($class, $x) = @_;
831              
832 0 0       0 return if $class -> _is_zero($x);
833              
834 0         0 my $str = $class -> _to_hex($x);
835              
836             # First do the bits in all but the most significant hex digit.
837              
838 0         0 my $y = $class -> _new(length($str) - 1);
839 0         0 $y = $class -> _mul($y, $class -> _new(4));
840              
841             # Now add the number of bits in the most significant hex digit.
842              
843 0         0 my $n = int log(hex(substr($str, 0, 1))) / log(2);
844 0         0 $y = $class -> _add($y, $class -> _new($n));
845              
846             # $y is now 1 too small unless $y is an exact power of 2.
847              
848 0         0 my $pow2 = $class -> _lsft($class -> _one(), $y, 2);
849 0 0       0 my $is_exact = $class -> _acmp($x, $pow2) == 0 ? 1 : 0;
850 0 0       0 $y = $class -> _inc($y) if $is_exact == 0;
851 0 0       0 return $y, $is_exact if wantarray;
852 0         0 return $y;
853             }
854              
855             sub _clog10 {
856 0     0   0 my ($class, $x) = @_;
857              
858 0 0       0 return if $class -> _is_zero($x);
859              
860 0         0 my $str = $class -> _str($x);
861 0         0 my $len = length($str);
862              
863 0 0       0 if ($str =~ /^10*$/) {
864 0         0 my $y = $class -> _new($len - 1);
865 0 0       0 return $y, 1 if wantarray;
866 0         0 return $y;
867             }
868              
869 0         0 my $y = $class -> _new($len);
870 0 0       0 return $y, 0 if wantarray;
871 0         0 return $y;
872             }
873              
874             sub _sqrt {
875             # square-root of $y in place
876 0     0   0 my ($class, $y) = @_;
877              
878 0 0       0 return $y if $class -> _is_zero($y);
879              
880 0         0 my $y_str = $class -> _str($y);
881 0         0 my $y_len = length($y_str);
882              
883             # Compute the guess $x.
884              
885 0         0 my $xm;
886             my $xe;
887 0 0       0 if ($y_len % 2 == 0) {
888 0         0 $xm = sqrt("." . $y_str);
889 0         0 $xe = $y_len / 2;
890 0         0 $xm = sprintf "%.0f", int($xm * 1e15);
891 0         0 $xe -= 15;
892             } else {
893 0         0 $xm = sqrt(".0" . $y_str);
894 0         0 $xe = ($y_len + 1) / 2;
895 0         0 $xm = sprintf "%.0f", int($xm * 1e16);
896 0         0 $xe -= 16;
897             }
898              
899 0         0 my $x;
900 0 0       0 if ($xe < 0) {
901 0         0 $x = substr $xm, 0, length($xm) + $xe;
902             } else {
903 0         0 $x = $xm . ("0" x $xe);
904             }
905              
906 0         0 $x = $class -> _new($x);
907              
908             # Newton's method for computing square root of y
909             #
910             # x(i+1) = x(i) - f(x(i)) / f'(x(i))
911             # = x(i) - (x(i)^2 - y) / (2 * x(i)) # use if x(i)^2 > y
912             # = x(i) + (y - x(i)^2) / (2 * x(i)) # use if x(i)^2 < y
913              
914             # Determine if x, our guess, is too small, correct, or too large.
915              
916 0         0 my $xsq = $class -> _mul($class -> _copy($x), $x); # x(i)^2
917 0         0 my $acmp = $class -> _acmp($xsq, $y); # x(i)^2 <=> y
918              
919             # Only assign a value to this variable if we will be using it.
920              
921 0         0 my $two;
922 0 0       0 $two = $class -> _two() if $acmp != 0;
923              
924             # If x is too small, do one iteration of Newton's method. Since the
925             # function f(x) = x^2 - y is concave and monotonically increasing, the next
926             # guess for x will either be correct or too large.
927              
928 0 0       0 if ($acmp < 0) {
929              
930             # x(i+1) = x(i) + (y - x(i)^2) / (2 * x(i))
931              
932 0         0 my $numer = $class -> _sub($class -> _copy($y), $xsq); # y - x(i)^2
933 0         0 my $denom = $class -> _mul($class -> _copy($two), $x); # 2 * x(i)
934 0         0 my $delta = $class -> _div($numer, $denom);
935              
936 0 0       0 unless ($class -> _is_zero($delta)) {
937 0         0 $x = $class -> _add($x, $delta);
938 0         0 $xsq = $class -> _mul($class -> _copy($x), $x); # x(i)^2
939 0         0 $acmp = $class -> _acmp($xsq, $y); # x(i)^2 <=> y
940             }
941             }
942              
943             # If our guess for x is too large, apply Newton's method repeatedly until
944             # we either have got the correct value, or the delta is zero.
945              
946 0         0 while ($acmp > 0) {
947              
948             # x(i+1) = x(i) - (x(i)^2 - y) / (2 * x(i))
949              
950 0         0 my $numer = $class -> _sub($xsq, $y); # x(i)^2 - y
951 0         0 my $denom = $class -> _mul($class -> _copy($two), $x); # 2 * x(i)
952 0         0 my $delta = $class -> _div($numer, $denom);
953 0 0       0 last if $class -> _is_zero($delta);
954              
955 0         0 $x = $class -> _sub($x, $delta);
956 0         0 $xsq = $class -> _mul($class -> _copy($x), $x); # x(i)^2
957 0         0 $acmp = $class -> _acmp($xsq, $y); # x(i)^2 <=> y
958             }
959              
960             # When the delta is zero, our value for x might still be too large. We
961             # require that the outout is either exact or too small (i.e., rounded down
962             # to the nearest integer), so do a final check.
963              
964 0         0 while ($acmp > 0) {
965 0         0 $x = $class -> _dec($x);
966 0         0 $xsq = $class -> _mul($class -> _copy($x), $x); # x(i)^2
967 0         0 $acmp = $class -> _acmp($xsq, $y); # x(i)^2 <=> y
968             }
969              
970 0         0 return $x;
971             }
972              
973             sub _root {
974 0     0   0 my ($class, $y, $n) = @_;
975              
976 0 0 0     0 return $y if $class -> _is_zero($y) || $class -> _is_one($y) ||
      0        
977             $class -> _is_one($n);
978              
979             # If y <= n, the result is always (truncated to) 1.
980              
981 0 0       0 return $class -> _one() if $class -> _acmp($y, $n) <= 0;
982              
983             # Compute the initial guess x of y^(1/n). When n is large, Newton's method
984             # converges slowly if the "guess" (initial value) is poor, so we need a
985             # good guess. It the guess is too small, the next guess will be too large,
986             # and from then on all guesses are too large.
987              
988 0         0 my $DEBUG = 0;
989              
990             # Split y into mantissa and exponent in base 10, so that
991             #
992             # y = xm * 10^xe, where 0 < xm < 1 and xe is an integer
993              
994 0         0 my $y_str = $class -> _str($y);
995 0         0 my $ym = "." . $y_str;
996 0         0 my $ye = length($y_str);
997              
998             # From this compute the approximate base 10 logarithm of y
999             #
1000             # log_10(y) = log_10(ym) + log_10(ye^10)
1001             # = log(ym)/log(10) + ye
1002              
1003 0         0 my $log10y = log($ym) / log(10) + $ye;
1004              
1005             # And from this compute the approximate base 10 logarithm of x, where
1006             # x = y^(1/n)
1007             #
1008             # log_10(x) = log_10(y)/n
1009              
1010 0         0 my $log10x = $log10y / $class -> _num($n);
1011              
1012             # From this compute xm and xe, the mantissa and exponent (in base 10) of x,
1013             # where 1 < xm <= 10 and xe is an integer.
1014              
1015 0         0 my $xe = int $log10x;
1016 0         0 my $xm = 10 ** ($log10x - $xe);
1017              
1018             # Scale the mantissa and exponent to increase the integer part of ym, which
1019             # gives us better accuracy.
1020              
1021 0 0       0 if ($DEBUG) {
1022 0         0 print "\n";
1023 0         0 print "y_str = $y_str\n";
1024 0         0 print "ym = $ym\n";
1025 0         0 print "ye = $ye\n";
1026 0         0 print "log10y = $log10y\n";
1027 0         0 print "log10x = $log10x\n";
1028 0         0 print "xm = $xm\n";
1029 0         0 print "xe = $xe\n";
1030             }
1031              
1032 0 0       0 my $d = $xe < 15 ? $xe : 15;
1033 0         0 $xm *= 10 ** $d;
1034 0         0 $xe -= $d;
1035              
1036 0 0       0 if ($DEBUG) {
1037 0         0 print "\n";
1038 0         0 print "xm = $xm\n";
1039 0         0 print "xe = $xe\n";
1040             }
1041              
1042             # If the mantissa is not an integer, round up to nearest integer, and then
1043             # convert the number to a string. It is important to always round up due to
1044             # how Newton's method behaves in this case. If the initial guess is too
1045             # small, the next guess will be too large, after which every succeeding
1046             # guess converges the correct value from above. Now, if the initial guess
1047             # is too small and n is large, the next guess will be much too large and
1048             # require a large number of iterations to get close to the solution.
1049             # Because of this, we are likely to find the solution faster if we make
1050             # sure the initial guess is not too small.
1051              
1052 0         0 my $xm_int = int($xm);
1053 0 0       0 my $x_str = sprintf '%.0f', $xm > $xm_int ? $xm_int + 1 : $xm_int;
1054 0         0 $x_str .= "0" x $xe;
1055              
1056 0         0 my $x = $class -> _new($x_str);
1057              
1058 0 0       0 if ($DEBUG) {
1059 0         0 print "xm = $xm\n";
1060 0         0 print "xe = $xe\n";
1061 0         0 print "\n";
1062 0         0 print "x_str = $x_str (initial guess)\n";
1063 0         0 print "\n";
1064             }
1065              
1066             # Use Newton's method for computing n'th root of y.
1067             #
1068             # x(i+1) = x(i) - f(x(i)) / f'(x(i))
1069             # = x(i) - (x(i)^n - y) / (n * x(i)^(n-1)) # use if x(i)^n > y
1070             # = x(i) + (y - x(i)^n) / (n * x(i)^(n-1)) # use if x(i)^n < y
1071              
1072             # Determine if x, our guess, is too small, correct, or too large. Rather
1073             # than computing x(i)^n and x(i)^(n-1) directly, compute x(i)^(n-1) and
1074             # then the same value multiplied by x.
1075              
1076 0         0 my $nm1 = $class -> _dec($class -> _copy($n)); # n-1
1077 0         0 my $xpownm1 = $class -> _pow($class -> _copy($x), $nm1); # x(i)^(n-1)
1078 0         0 my $xpown = $class -> _mul($class -> _copy($xpownm1), $x); # x(i)^n
1079 0         0 my $acmp = $class -> _acmp($xpown, $y); # x(i)^n <=> y
1080              
1081 0 0       0 if ($DEBUG) {
1082 0         0 print "\n";
1083 0         0 print "x = ", $class -> _str($x), "\n";
1084 0         0 print "x^n = ", $class -> _str($xpown), "\n";
1085 0         0 print "y = ", $class -> _str($y), "\n";
1086 0         0 print "acmp = $acmp\n";
1087             }
1088              
1089             # If x is too small, do one iteration of Newton's method. Since the
1090             # function f(x) = x^n - y is concave and monotonically increasing, the next
1091             # guess for x will either be correct or too large.
1092              
1093 0 0       0 if ($acmp < 0) {
1094              
1095             # x(i+1) = x(i) + (y - x(i)^n) / (n * x(i)^(n-1))
1096              
1097 0         0 my $numer = $class -> _sub($class -> _copy($y), $xpown); # y - x(i)^n
1098 0         0 my $denom = $class -> _mul($class -> _copy($n), $xpownm1); # n * x(i)^(n-1)
1099 0         0 my $delta = $class -> _div($numer, $denom);
1100              
1101 0 0       0 if ($DEBUG) {
1102 0         0 print "\n";
1103 0         0 print "numer = ", $class -> _str($numer), "\n";
1104 0         0 print "denom = ", $class -> _str($denom), "\n";
1105 0         0 print "delta = ", $class -> _str($delta), "\n";
1106             }
1107              
1108 0 0       0 unless ($class -> _is_zero($delta)) {
1109 0         0 $x = $class -> _add($x, $delta);
1110 0         0 $xpownm1 = $class -> _pow($class -> _copy($x), $nm1); # x(i)^(n-1)
1111 0         0 $xpown = $class -> _mul($class -> _copy($xpownm1), $x); # x(i)^n
1112 0         0 $acmp = $class -> _acmp($xpown, $y); # x(i)^n <=> y
1113              
1114 0 0       0 if ($DEBUG) {
1115 0         0 print "\n";
1116 0         0 print "x = ", $class -> _str($x), "\n";
1117 0         0 print "x^n = ", $class -> _str($xpown), "\n";
1118 0         0 print "y = ", $class -> _str($y), "\n";
1119 0         0 print "acmp = $acmp\n";
1120             }
1121             }
1122             }
1123              
1124             # If our guess for x is too large, apply Newton's method repeatedly until
1125             # we either have got the correct value, or the delta is zero.
1126              
1127 0         0 while ($acmp > 0) {
1128              
1129             # x(i+1) = x(i) - (x(i)^n - y) / (n * x(i)^(n-1))
1130              
1131 0         0 my $numer = $class -> _sub($class -> _copy($xpown), $y); # x(i)^n - y
1132 0         0 my $denom = $class -> _mul($class -> _copy($n), $xpownm1); # n * x(i)^(n-1)
1133              
1134 0 0       0 if ($DEBUG) {
1135 0         0 print "numer = ", $class -> _str($numer), "\n";
1136 0         0 print "denom = ", $class -> _str($denom), "\n";
1137             }
1138              
1139 0         0 my $delta = $class -> _div($numer, $denom);
1140              
1141 0 0       0 if ($DEBUG) {
1142 0         0 print "delta = ", $class -> _str($delta), "\n";
1143             }
1144              
1145 0 0       0 last if $class -> _is_zero($delta);
1146              
1147 0         0 $x = $class -> _sub($x, $delta);
1148 0         0 $xpownm1 = $class -> _pow($class -> _copy($x), $nm1); # x(i)^(n-1)
1149 0         0 $xpown = $class -> _mul($class -> _copy($xpownm1), $x); # x(i)^n
1150 0         0 $acmp = $class -> _acmp($xpown, $y); # x(i)^n <=> y
1151              
1152 0 0       0 if ($DEBUG) {
1153 0         0 print "\n";
1154 0         0 print "x = ", $class -> _str($x), "\n";
1155 0         0 print "x^n = ", $class -> _str($xpown), "\n";
1156 0         0 print "y = ", $class -> _str($y), "\n";
1157 0         0 print "acmp = $acmp\n";
1158             }
1159             }
1160              
1161             # When the delta is zero, our value for x might still be too large. We
1162             # require that the outout is either exact or too small (i.e., rounded down
1163             # to the nearest integer), so do a final check.
1164              
1165 0         0 while ($acmp > 0) {
1166 0         0 $x = $class -> _dec($x);
1167 0         0 $xpown = $class -> _pow($class -> _copy($x), $n); # x(i)^n
1168 0         0 $acmp = $class -> _acmp($xpown, $y); # x(i)^n <=> y
1169             }
1170              
1171 0         0 return $x;
1172             }
1173              
1174             ##############################################################################
1175             # binary stuff
1176              
1177             sub _and {
1178 0     0   0 my ($class, $x, $y) = @_;
1179              
1180 0 0       0 return $x if $class -> _acmp($x, $y) == 0;
1181              
1182 0         0 my $m = $class -> _one();
1183 0         0 my $mask = $class -> _new("32768");
1184              
1185 0         0 my ($xr, $yr); # remainders after division
1186              
1187 0         0 my $xc = $class -> _copy($x);
1188 0         0 my $yc = $class -> _copy($y);
1189 0         0 my $z = $class -> _zero();
1190              
1191 0   0     0 until ($class -> _is_zero($xc) || $class -> _is_zero($yc)) {
1192 0         0 ($xc, $xr) = $class -> _div($xc, $mask);
1193 0         0 ($yc, $yr) = $class -> _div($yc, $mask);
1194 0         0 my $bits = $class -> _new($class -> _num($xr) & $class -> _num($yr));
1195 0         0 $z = $class -> _add($z, $class -> _mul($bits, $m));
1196 0         0 $m = $class -> _mul($m, $mask);
1197             }
1198              
1199 0         0 return $z;
1200             }
1201              
1202             sub _xor {
1203 0     0   0 my ($class, $x, $y) = @_;
1204              
1205 0 0       0 return $class -> _zero() if $class -> _acmp($x, $y) == 0;
1206              
1207 0         0 my $m = $class -> _one();
1208 0         0 my $mask = $class -> _new("32768");
1209              
1210 0         0 my ($xr, $yr); # remainders after division
1211              
1212 0         0 my $xc = $class -> _copy($x);
1213 0         0 my $yc = $class -> _copy($y);
1214 0         0 my $z = $class -> _zero();
1215              
1216 0   0     0 until ($class -> _is_zero($xc) || $class -> _is_zero($yc)) {
1217 0         0 ($xc, $xr) = $class -> _div($xc, $mask);
1218 0         0 ($yc, $yr) = $class -> _div($yc, $mask);
1219 0         0 my $bits = $class -> _new($class -> _num($xr) ^ $class -> _num($yr));
1220 0         0 $z = $class -> _add($z, $class -> _mul($bits, $m));
1221 0         0 $m = $class -> _mul($m, $mask);
1222             }
1223              
1224             # The loop above stops when the smallest of the two numbers is exhausted.
1225             # The remainder of the longer one will survive bit-by-bit, so we simple
1226             # multiply-add it in.
1227              
1228 0 0       0 $z = $class -> _add($z, $class -> _mul($xc, $m))
1229             unless $class -> _is_zero($xc);
1230 0 0       0 $z = $class -> _add($z, $class -> _mul($yc, $m))
1231             unless $class -> _is_zero($yc);
1232              
1233 0         0 return $z;
1234             }
1235              
1236             sub _or {
1237 0     0   0 my ($class, $x, $y) = @_;
1238              
1239 0 0       0 return $x if $class -> _acmp($x, $y) == 0; # shortcut (see _and)
1240              
1241 0         0 my $m = $class -> _one();
1242 0         0 my $mask = $class -> _new("32768");
1243              
1244 0         0 my ($xr, $yr); # remainders after division
1245              
1246 0         0 my $xc = $class -> _copy($x);
1247 0         0 my $yc = $class -> _copy($y);
1248 0         0 my $z = $class -> _zero();
1249              
1250 0   0     0 until ($class -> _is_zero($xc) || $class -> _is_zero($yc)) {
1251 0         0 ($xc, $xr) = $class -> _div($xc, $mask);
1252 0         0 ($yc, $yr) = $class -> _div($yc, $mask);
1253 0         0 my $bits = $class -> _new($class -> _num($xr) | $class -> _num($yr));
1254 0         0 $z = $class -> _add($z, $class -> _mul($bits, $m));
1255 0         0 $m = $class -> _mul($m, $mask);
1256             }
1257              
1258             # The loop above stops when the smallest of the two numbers is exhausted.
1259             # The remainder of the longer one will survive bit-by-bit, so we simple
1260             # multiply-add it in.
1261              
1262 0 0       0 $z = $class -> _add($z, $class -> _mul($xc, $m))
1263             unless $class -> _is_zero($xc);
1264 0 0       0 $z = $class -> _add($z, $class -> _mul($yc, $m))
1265             unless $class -> _is_zero($yc);
1266              
1267 0         0 return $z;
1268             }
1269              
1270             sub _sand {
1271 33     33   78 my ($class, $x, $sx, $y, $sy) = @_;
1272              
1273 33 50 33     95 return ($class -> _zero(), '+')
1274             if $class -> _is_zero($x) || $class -> _is_zero($y);
1275              
1276 33 100 100     253 my $sign = $sx eq '-' && $sy eq '-' ? '-' : '+';
1277              
1278 33         49 my ($bx, $by);
1279              
1280 33 100       60 if ($sx eq '-') { # if x is negative
1281             # two's complement: inc (dec unsigned value) and flip all "bits" in $bx
1282 24         50 $bx = $class -> _copy($x);
1283 24         63 $bx = $class -> _dec($bx);
1284 24         75 $bx = $class -> _as_hex($bx);
1285 24         111 $bx =~ s/^-?0x//;
1286 24         43 $bx =~ tr<0123456789abcdef>
1287             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1288             } else { # if x is positive
1289 9         39 $bx = $class -> _as_hex($x); # get binary representation
1290 9         47 $bx =~ s/^-?0x//;
1291 9         20 $bx =~ tr
1292             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1293             }
1294              
1295 33 100       66 if ($sy eq '-') { # if y is negative
1296             # two's complement: inc (dec unsigned value) and flip all "bits" in $by
1297 25         57 $by = $class -> _copy($y);
1298 25         64 $by = $class -> _dec($by);
1299 25         54 $by = $class -> _as_hex($by);
1300 25         84 $by =~ s/^-?0x//;
1301 25         39 $by =~ tr<0123456789abcdef>
1302             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1303             } else {
1304 8         21 $by = $class -> _as_hex($y); # get binary representation
1305 8         24 $by =~ s/^-?0x//;
1306 8         17 $by =~ tr
1307             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1308             }
1309              
1310             # now we have bit-strings from X and Y, reverse them for padding
1311 33         64 $bx = reverse $bx;
1312 33         48 $by = reverse $by;
1313              
1314             # padd the shorter string
1315 33 100       43 my $xx = "\x00"; $xx = "\x0f" if $sx eq '-';
  33         75  
1316 33 100       39 my $yy = "\x00"; $yy = "\x0f" if $sy eq '-';
  33         75  
1317 33         49 my $diff = CORE::length($bx) - CORE::length($by);
1318 33 100       128 if ($diff > 0) {
    50          
1319             # if $yy eq "\x00", we can cut $bx, otherwise we need to padd $by
1320 9         29 $by .= $yy x $diff;
1321             } elsif ($diff < 0) {
1322             # if $xx eq "\x00", we can cut $by, otherwise we need to padd $bx
1323 0         0 $bx .= $xx x abs($diff);
1324             }
1325              
1326             # and the strings together
1327 33         60 my $r = $bx & $by;
1328              
1329             # and reverse the result again
1330 33         47 $bx = reverse $r;
1331              
1332             # One of $bx or $by was negative, so need to flip bits in the result. In both
1333             # cases (one or two of them negative, or both positive) we need to get the
1334             # characters back.
1335 33 100       53 if ($sign eq '-') {
1336 16         24 $bx =~ tr<\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>
1337             <0123456789abcdef>;
1338             } else {
1339 17         28 $bx =~ tr<\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>
1340             ;
1341             }
1342              
1343             # leading zeros will be stripped by _from_hex()
1344 33         79 $bx = '0x' . $bx;
1345 33         115 $bx = $class -> _from_hex($bx);
1346              
1347 33 100       93 $bx = $class -> _inc($bx) if $sign eq '-';
1348              
1349             # avoid negative zero
1350 33 100       79 $sign = '+' if $class -> _is_zero($bx);
1351              
1352 33         155 return $bx, $sign;
1353             }
1354              
1355             sub _sxor {
1356 40     40   123 my ($class, $x, $sx, $y, $sy) = @_;
1357              
1358 40 50 33     157 return ($class -> _zero(), '+')
1359             if $class -> _is_zero($x) && $class -> _is_zero($y);
1360              
1361 40 100       124 my $sign = $sx ne $sy ? '-' : '+';
1362              
1363 40         68 my ($bx, $by);
1364              
1365 40 100       102 if ($sx eq '-') { # if x is negative
1366             # two's complement: inc (dec unsigned value) and flip all "bits" in $bx
1367 27         81 $bx = $class -> _copy($x);
1368 27         113 $bx = $class -> _dec($bx);
1369 27         154 $bx = $class -> _as_hex($bx);
1370 27         181 $bx =~ s/^-?0x//;
1371 27         68 $bx =~ tr<0123456789abcdef>
1372             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1373             } else { # if x is positive
1374 13         56 $bx = $class -> _as_hex($x); # get binary representation
1375 13         74 $bx =~ s/^-?0x//;
1376 13         29 $bx =~ tr
1377             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1378             }
1379              
1380 40 100       108 if ($sy eq '-') { # if y is negative
1381             # two's complement: inc (dec unsigned value) and flip all "bits" in $by
1382 29         93 $by = $class -> _copy($y);
1383 29         96 $by = $class -> _dec($by);
1384 29         84 $by = $class -> _as_hex($by);
1385 29         143 $by =~ s/^-?0x//;
1386 29         64 $by =~ tr<0123456789abcdef>
1387             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1388             } else {
1389 11         42 $by = $class -> _as_hex($y); # get binary representation
1390 11         59 $by =~ s/^-?0x//;
1391 11         31 $by =~ tr
1392             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1393             }
1394              
1395             # now we have bit-strings from X and Y, reverse them for padding
1396 40         106 $bx = reverse $bx;
1397 40         78 $by = reverse $by;
1398              
1399             # padd the shorter string
1400 40 100       87 my $xx = "\x00"; $xx = "\x0f" if $sx eq '-';
  40         131  
1401 40 100       77 my $yy = "\x00"; $yy = "\x0f" if $sy eq '-';
  40         104  
1402 40         80 my $diff = CORE::length($bx) - CORE::length($by);
1403 40 100       124 if ($diff > 0) {
    100          
1404             # if $yy eq "\x00", we can cut $bx, otherwise we need to padd $by
1405 9         25 $by .= $yy x $diff;
1406             } elsif ($diff < 0) {
1407             # if $xx eq "\x00", we can cut $by, otherwise we need to padd $bx
1408 3         13 $bx .= $xx x abs($diff);
1409             }
1410              
1411             # xor the strings together
1412 40         102 my $r = $bx ^ $by;
1413              
1414             # and reverse the result again
1415 40         76 $bx = reverse $r;
1416              
1417             # One of $bx or $by was negative, so need to flip bits in the result. In both
1418             # cases (one or two of them negative, or both positive) we need to get the
1419             # characters back.
1420 40 100       92 if ($sign eq '-') {
1421 24         47 $bx =~ tr<\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>
1422             <0123456789abcdef>;
1423             } else {
1424 16         31 $bx =~ tr<\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>
1425             ;
1426             }
1427              
1428             # leading zeros will be stripped by _from_hex()
1429 40         86 $bx = '0x' . $bx;
1430 40         222 $bx = $class -> _from_hex($bx);
1431              
1432 40 100       168 $bx = $class -> _inc($bx) if $sign eq '-';
1433              
1434             # avoid negative zero
1435 40 100       117 $sign = '+' if $class -> _is_zero($bx);
1436              
1437 40         238 return $bx, $sign;
1438             }
1439              
1440             sub _sor {
1441 35     35   154 my ($class, $x, $sx, $y, $sy) = @_;
1442              
1443 35 50 33     126 return ($class -> _zero(), '+')
1444             if $class -> _is_zero($x) && $class -> _is_zero($y);
1445              
1446 35 50 66     129 my $sign = $sx eq '-' || $sy eq '-' ? '-' : '+';
1447              
1448 35         56 my ($bx, $by);
1449              
1450 35 100       76 if ($sx eq '-') { # if x is negative
1451             # two's complement: inc (dec unsigned value) and flip all "bits" in $bx
1452 23         75 $bx = $class -> _copy($x);
1453 23         92 $bx = $class -> _dec($bx);
1454 23         89 $bx = $class -> _as_hex($bx);
1455 23         138 $bx =~ s/^-?0x//;
1456 23         59 $bx =~ tr<0123456789abcdef>
1457             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1458             } else { # if x is positive
1459 12         46 $bx = $class -> _as_hex($x); # get binary representation
1460 12         69 $bx =~ s/^-?0x//;
1461 12         29 $bx =~ tr
1462             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1463             }
1464              
1465 35 100       86 if ($sy eq '-') { # if y is negative
1466             # two's complement: inc (dec unsigned value) and flip all "bits" in $by
1467 24         71 $by = $class -> _copy($y);
1468 24         67 $by = $class -> _dec($by);
1469 24         73 $by = $class -> _as_hex($by);
1470 24         102 $by =~ s/^-?0x//;
1471 24         41 $by =~ tr<0123456789abcdef>
1472             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1473             } else {
1474 11         47 $by = $class -> _as_hex($y); # get binary representation
1475 11         46 $by =~ s/^-?0x//;
1476 11         23 $by =~ tr
1477             <\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>;
1478             }
1479              
1480             # now we have bit-strings from X and Y, reverse them for padding
1481 35         88 $bx = reverse $bx;
1482 35         57 $by = reverse $by;
1483              
1484             # padd the shorter string
1485 35 100       58 my $xx = "\x00"; $xx = "\x0f" if $sx eq '-';
  35         97  
1486 35 100       52 my $yy = "\x00"; $yy = "\x0f" if $sy eq '-';
  35         91  
1487 35         70 my $diff = CORE::length($bx) - CORE::length($by);
1488 35 100       105 if ($diff > 0) {
    100          
1489             # if $yy eq "\x00", we can cut $bx, otherwise we need to padd $by
1490 12         30 $by .= $yy x $diff;
1491             } elsif ($diff < 0) {
1492             # if $xx eq "\x00", we can cut $by, otherwise we need to padd $bx
1493 3         17 $bx .= $xx x abs($diff);
1494             }
1495              
1496             # or the strings together
1497 35         111 my $r = $bx | $by;
1498              
1499             # and reverse the result again
1500 35         61 $bx = reverse $r;
1501              
1502             # One of $bx or $by was negative, so need to flip bits in the result. In both
1503             # cases (one or two of them negative, or both positive) we need to get the
1504             # characters back.
1505 35 50       69 if ($sign eq '-') {
1506 35         58 $bx =~ tr<\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>
1507             <0123456789abcdef>;
1508             } else {
1509 0         0 $bx =~ tr<\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00>
1510             ;
1511             }
1512              
1513             # leading zeros will be stripped by _from_hex()
1514 35         66 $bx = '0x' . $bx;
1515 35         124 $bx = $class -> _from_hex($bx);
1516              
1517 35 50       146 $bx = $class -> _inc($bx) if $sign eq '-';
1518              
1519             # avoid negative zero
1520 35 50       114 $sign = '+' if $class -> _is_zero($bx);
1521              
1522 35         192 return $bx, $sign;
1523             }
1524              
1525             sub _to_bin {
1526             # convert the number to a string of binary digits without prefix
1527 369     369   903 my ($class, $x) = @_;
1528 369         802 my $str = '';
1529 369         1175 my $tmp = $class -> _copy($x);
1530 369         1128 my $chunk = $class -> _new("16777216"); # 2^24 = 24 binary digits
1531 369         613 my $rem;
1532 369         1563 until ($class -> _acmp($tmp, $chunk) < 0) {
1533 83         298 ($tmp, $rem) = $class -> _div($tmp, $chunk);
1534 83         299 $str = sprintf("%024b", $class -> _num($rem)) . $str;
1535             }
1536 369 100       1240 unless ($class -> _is_zero($tmp)) {
1537 318         1263 $str = sprintf("%b", $class -> _num($tmp)) . $str;
1538             }
1539 369 100       1937 return length($str) ? $str : '0';
1540             }
1541              
1542             sub _to_oct {
1543             # convert the number to a string of octal digits without prefix
1544 48     48   118 my ($class, $x) = @_;
1545 48         112 my $str = '';
1546 48         140 my $tmp = $class -> _copy($x);
1547 48         179 my $chunk = $class -> _new("16777216"); # 2^24 = 8 octal digits
1548 48         105 my $rem;
1549 48         200 until ($class -> _acmp($tmp, $chunk) < 0) {
1550 24         103 ($tmp, $rem) = $class -> _div($tmp, $chunk);
1551 24         100 $str = sprintf("%08o", $class -> _num($rem)) . $str;
1552             }
1553 48 100       168 unless ($class -> _is_zero($tmp)) {
1554 40         183 $str = sprintf("%o", $class -> _num($tmp)) . $str;
1555             }
1556 48 100       241 return length($str) ? $str : '0';
1557             }
1558              
1559             sub _to_hex {
1560             # convert the number to a string of hexadecimal digits without prefix
1561 40     40   102 my ($class, $x) = @_;
1562 40         95 my $str = '';
1563 40         129 my $tmp = $class -> _copy($x);
1564 40         127 my $chunk = $class -> _new("16777216"); # 2^24 = 6 hexadecimal digits
1565 40         69 my $rem;
1566 40         214 until ($class -> _acmp($tmp, $chunk) < 0) {
1567 16         79 ($tmp, $rem) = $class -> _div($tmp, $chunk);
1568 16         80 $str = sprintf("%06x", $class -> _num($rem)) . $str;
1569             }
1570 40 100       154 unless ($class -> _is_zero($tmp)) {
1571 32         125 $str = sprintf("%x", $class -> _num($tmp)) . $str;
1572             }
1573 40 100       227 return length($str) ? $str : '0';
1574             }
1575              
1576             sub _as_bin {
1577             # convert the number to a string of binary digits with prefix
1578 0     0   0 my ($class, $x) = @_;
1579 0         0 return '0b' . $class -> _to_bin($x);
1580             }
1581              
1582             sub _as_oct {
1583             # convert the number to a string of octal digits with prefix
1584 0     0   0 my ($class, $x) = @_;
1585 0         0 return '0' . $class -> _to_oct($x); # yes, 0 becomes "00"
1586             }
1587              
1588             sub _as_hex {
1589             # convert the number to a string of hexadecimal digits with prefix
1590 0     0   0 my ($class, $x) = @_;
1591 0         0 return '0x' . $class -> _to_hex($x);
1592             }
1593              
1594             sub _to_bytes {
1595             # convert the number to a string of bytes
1596 0     0   0 my ($class, $x) = @_;
1597 0         0 my $str = '';
1598 0         0 my $tmp = $class -> _copy($x);
1599 0         0 my $chunk = $class -> _new("65536");
1600 0         0 my $rem;
1601 0         0 until ($class -> _is_zero($tmp)) {
1602 0         0 ($tmp, $rem) = $class -> _div($tmp, $chunk);
1603 0         0 $str = pack('n', $class -> _num($rem)) . $str;
1604             }
1605 0         0 $str =~ s/^\0+//;
1606 0 0       0 return length($str) ? $str : "\x00";
1607             }
1608              
1609             *_as_bytes = \&_to_bytes;
1610              
1611             sub _to_base {
1612             # convert the number to a string of digits in various bases
1613 0     0   0 my $class = shift;
1614 0         0 my $x = shift;
1615 0         0 my $base = shift;
1616 0 0       0 $base = $class -> _new($base) unless ref($base);
1617              
1618 0         0 my $collseq;
1619 0 0       0 if (@_) {
1620 0         0 $collseq = shift;
1621 0 0 0     0 croak "The collation sequence must be a non-empty string"
1622             unless defined($collseq) && length($collseq);
1623             } else {
1624 0 0       0 if ($class -> _acmp($base, $class -> _new("94")) <= 0) {
1625 0         0 $collseq = '0123456789' # 48 .. 57
1626             . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' # 65 .. 90
1627             . 'abcdefghijklmnopqrstuvwxyz' # 97 .. 122
1628             . '!"#$%&\'()*+,-./' # 33 .. 47
1629             . ':;<=>?@' # 58 .. 64
1630             . '[\\]^_`' # 91 .. 96
1631             . '{|}~'; # 123 .. 126
1632             } else {
1633 0         0 croak "When base > 94, a collation sequence must be given";
1634             }
1635             }
1636              
1637 0         0 my @collseq = split '', $collseq;
1638              
1639 0         0 my $str = '';
1640 0         0 my $tmp = $class -> _copy($x);
1641 0         0 my $rem;
1642 0         0 until ($class -> _is_zero($tmp)) {
1643 0         0 ($tmp, $rem) = $class -> _div($tmp, $base);
1644 0         0 my $num = $class -> _num($rem);
1645 0 0       0 croak "no character to represent '$num' in collation sequence",
1646             " (collation sequence is too short)" if $num > $#collseq;
1647 0         0 my $chr = $collseq[$num];
1648 0         0 $str = $chr . $str;
1649             }
1650 0 0       0 return $collseq[0] unless length $str;
1651 0         0 return $str;
1652             }
1653              
1654             sub _to_base_num {
1655             # Convert the number to an array of integers in any base.
1656 0     0   0 my ($class, $x, $base) = @_;
1657              
1658             # Make sure the base is an object and >= 2.
1659 0 0       0 $base = $class -> _new($base) unless ref($base);
1660 0         0 my $two = $class -> _two();
1661 0 0       0 croak "base must be >= 2" unless $class -> _acmp($base, $two) >= 0;
1662              
1663 0         0 my $out = [];
1664 0         0 my $xcopy = $class -> _copy($x);
1665 0         0 my $rem;
1666              
1667             # Do all except the last (most significant) element.
1668 0         0 until ($class -> _acmp($xcopy, $base) < 0) {
1669 0         0 ($xcopy, $rem) = $class -> _div($xcopy, $base);
1670 0         0 unshift @$out, $rem;
1671             }
1672              
1673             # Do the last (most significant element).
1674 0 0       0 unless ($class -> _is_zero($xcopy)) {
1675 0         0 unshift @$out, $xcopy;
1676             }
1677              
1678             # $out is empty if $x is zero.
1679 0 0       0 unshift @$out, $class -> _zero() unless @$out;
1680              
1681 0         0 return $out;
1682             }
1683              
1684             sub _from_hex {
1685             # Convert a string of hexadecimal digits to a number.
1686              
1687 0     0   0 my ($class, $hex) = @_;
1688 0         0 $hex =~ s/^0[xX]//;
1689              
1690             # Find the largest number of hexadecimal digits that we can safely use with
1691             # 32 bit integers. There are 4 bits pr hexadecimal digit, and we use only
1692             # 31 bits to play safe. This gives us int(31 / 4) = 7.
1693              
1694 0         0 my $len = length $hex;
1695 0         0 my $rem = 1 + ($len - 1) % 7;
1696              
1697             # Do the first chunk.
1698              
1699 0         0 my $ret = $class -> _new(int hex substr $hex, 0, $rem);
1700 0 0       0 return $ret if $rem == $len;
1701              
1702             # Do the remaining chunks, if any.
1703              
1704 0         0 my $shift = $class -> _new(1 << (4 * 7));
1705 0         0 for (my $offset = $rem ; $offset < $len ; $offset += 7) {
1706 0         0 my $part = int hex substr $hex, $offset, 7;
1707 0         0 $ret = $class -> _mul($ret, $shift);
1708 0         0 $ret = $class -> _add($ret, $class -> _new($part));
1709             }
1710              
1711 0         0 return $ret;
1712             }
1713              
1714             sub _from_oct {
1715             # Convert a string of octal digits to a number.
1716              
1717 0     0   0 my ($class, $oct) = @_;
1718              
1719             # Find the largest number of octal digits that we can safely use with 32
1720             # bit integers. There are 3 bits pr octal digit, and we use only 31 bits to
1721             # play safe. This gives us int(31 / 3) = 10.
1722              
1723 0         0 my $len = length $oct;
1724 0         0 my $rem = 1 + ($len - 1) % 10;
1725              
1726             # Do the first chunk.
1727              
1728 0         0 my $ret = $class -> _new(int oct substr $oct, 0, $rem);
1729 0 0       0 return $ret if $rem == $len;
1730              
1731             # Do the remaining chunks, if any.
1732              
1733 0         0 my $shift = $class -> _new(1 << (3 * 10));
1734 0         0 for (my $offset = $rem ; $offset < $len ; $offset += 10) {
1735 0         0 my $part = int oct substr $oct, $offset, 10;
1736 0         0 $ret = $class -> _mul($ret, $shift);
1737 0         0 $ret = $class -> _add($ret, $class -> _new($part));
1738             }
1739              
1740 0         0 return $ret;
1741             }
1742              
1743             sub _from_bin {
1744             # Convert a string of binary digits to a number.
1745              
1746 0     0   0 my ($class, $bin) = @_;
1747 0         0 $bin =~ s/^0[bB]//;
1748              
1749             # The largest number of binary digits that we can safely use with 32 bit
1750             # integers is 31. We use only 31 bits to play safe.
1751              
1752 0         0 my $len = length $bin;
1753 0         0 my $rem = 1 + ($len - 1) % 31;
1754              
1755             # Do the first chunk.
1756              
1757 0         0 my $ret = $class -> _new(int oct '0b' . substr $bin, 0, $rem);
1758 0 0       0 return $ret if $rem == $len;
1759              
1760             # Do the remaining chunks, if any.
1761              
1762 0         0 my $shift = $class -> _new(1 << 31);
1763 0         0 for (my $offset = $rem ; $offset < $len ; $offset += 31) {
1764 0         0 my $part = int oct '0b' . substr $bin, $offset, 31;
1765 0         0 $ret = $class -> _mul($ret, $shift);
1766 0         0 $ret = $class -> _add($ret, $class -> _new($part));
1767             }
1768              
1769 0         0 return $ret;
1770             }
1771              
1772             sub _from_bytes {
1773             # convert string of bytes to a number
1774 0     0   0 my ($class, $str) = @_;
1775 0         0 my $x = $class -> _zero();
1776 0         0 my $base = $class -> _new("256");
1777 0         0 my $n = length($str);
1778 0         0 for (my $i = 0 ; $i < $n ; ++$i) {
1779 0         0 $x = $class -> _mul($x, $base);
1780 0         0 my $byteval = $class -> _new(unpack 'C', substr($str, $i, 1));
1781 0         0 $x = $class -> _add($x, $byteval);
1782             }
1783 0         0 return $x;
1784             }
1785              
1786             sub _from_base {
1787             # convert a string to a decimal number
1788 0     0   0 my $class = shift;
1789 0         0 my $str = shift;
1790 0         0 my $base = shift;
1791 0 0       0 $base = $class -> _new($base) unless ref($base);
1792              
1793 0         0 my $n = length($str);
1794 0         0 my $x = $class -> _zero();
1795              
1796 0         0 my $collseq;
1797 0 0       0 if (@_) {
1798 0         0 $collseq = shift();
1799             } else {
1800 0 0       0 if ($class -> _acmp($base, $class -> _new("36")) <= 0) {
    0          
1801 0         0 $str = uc $str;
1802 0         0 $collseq = '0123456789' . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
1803             } elsif ($class -> _acmp($base, $class -> _new("94")) <= 0) {
1804 0         0 $collseq = '0123456789' # 48 .. 57
1805             . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' # 65 .. 90
1806             . 'abcdefghijklmnopqrstuvwxyz' # 97 .. 122
1807             . '!"#$%&\'()*+,-./' # 33 .. 47
1808             . ':;<=>?@' # 58 .. 64
1809             . '[\\]^_`' # 91 .. 96
1810             . '{|}~'; # 123 .. 126
1811             } else {
1812 0         0 croak "When base > 94, a collation sequence must be given";
1813             }
1814 0         0 $collseq = substr $collseq, 0, $class -> _num($base);
1815             }
1816              
1817             # Create a mapping from each character in the collation sequence to the
1818             # corresponding integer. Check for duplicates in the collation sequence.
1819              
1820 0         0 my @collseq = split '', $collseq;
1821 0         0 my %collseq;
1822 0         0 for my $num (0 .. $#collseq) {
1823 0         0 my $chr = $collseq[$num];
1824             die "duplicate character '$chr' in collation sequence"
1825 0 0       0 if exists $collseq{$chr};
1826 0         0 $collseq{$chr} = $num;
1827             }
1828              
1829 0         0 for (my $i = 0 ; $i < $n ; ++$i) {
1830 0         0 my $chr = substr($str, $i, 1);
1831             die "input character '$chr' does not exist in collation sequence"
1832 0 0       0 unless exists $collseq{$chr};
1833 0         0 $x = $class -> _mul($x, $base);
1834 0         0 my $num = $class -> _new($collseq{$chr});
1835 0         0 $x = $class -> _add($x, $num);
1836             }
1837              
1838 0         0 return $x;
1839             }
1840              
1841             sub _from_base_num {
1842             # Convert an array in the given base to a number.
1843 0     0   0 my ($class, $in, $base) = @_;
1844              
1845             # Make sure the base is an object and >= 2.
1846 0 0       0 $base = $class -> _new($base) unless ref($base);
1847 0         0 my $two = $class -> _two();
1848 0 0       0 croak "base must be >= 2" unless $class -> _acmp($base, $two) >= 0;
1849              
1850             # @$in = map { ref($_) ? $_ : $class -> _new($_) } @$in;
1851              
1852 0         0 my $ele = $in -> [0];
1853              
1854 0 0       0 $ele = $class -> _new($ele) unless ref($ele);
1855 0         0 my $x = $class -> _copy($ele);
1856              
1857 0         0 for my $i (1 .. $#$in) {
1858 0         0 $x = $class -> _mul($x, $base);
1859 0         0 $ele = $in -> [$i];
1860 0 0       0 $ele = $class -> _new($ele) unless ref($ele);
1861 0         0 $x = $class -> _add($x, $ele);
1862             }
1863              
1864 0         0 return $x;
1865             }
1866              
1867             ##############################################################################
1868             # special modulus functions
1869              
1870             sub _modinv {
1871             # modular multiplicative inverse
1872 0     0   0 my ($class, $x, $y) = @_;
1873              
1874             # modulo zero
1875 0 0       0 if ($class -> _is_zero($y)) {
1876 0         0 return;
1877             }
1878              
1879             # modulo one
1880 0 0       0 if ($class -> _is_one($y)) {
1881 0         0 return ($class -> _zero(), '+');
1882             }
1883              
1884 0         0 my $u = $class -> _zero();
1885 0         0 my $v = $class -> _one();
1886 0         0 my $a = $class -> _copy($y);
1887 0         0 my $b = $class -> _copy($x);
1888              
1889             # Euclid's Algorithm for bgcd().
1890              
1891 0         0 my $q;
1892 0         0 my $sign = 1;
1893             {
1894 0         0 ($a, $q, $b) = ($b, $class -> _div($a, $b));
  0         0  
1895 0 0       0 last if $class -> _is_zero($b);
1896              
1897 0         0 my $vq = $class -> _mul($class -> _copy($v), $q);
1898 0         0 my $t = $class -> _add($vq, $u);
1899 0         0 $u = $v;
1900 0         0 $v = $t;
1901 0         0 $sign = -$sign;
1902 0         0 redo;
1903             }
1904              
1905             # if the gcd is not 1, there exists no modular multiplicative inverse
1906 0 0       0 return unless $class -> _is_one($a);
1907              
1908 0 0       0 ($v, $sign == 1 ? '+' : '-');
1909             }
1910              
1911             sub _modpow {
1912             # modulus of power ($x ** $y) % $z
1913 0     0   0 my ($class, $num, $exp, $mod) = @_;
1914              
1915             # a^b (mod 1) = 0 for all a and b
1916 0 0       0 if ($class -> _is_one($mod)) {
1917 0         0 return $class -> _zero();
1918             }
1919              
1920             # 0^a (mod m) = 0 if m != 0, a != 0
1921             # 0^0 (mod m) = 1 if m != 0
1922 0 0       0 if ($class -> _is_zero($num)) {
1923 0 0       0 return $class -> _is_zero($exp) ? $class -> _one()
1924             : $class -> _zero();
1925             }
1926              
1927             # We could do the following, but it doesn't actually save any time. The
1928             # _copy() is needed in case $num and $mod are the same object.
1929              
1930 0         0 $num = $class -> _mod($class -> _copy($num), $mod);
1931              
1932 0         0 my $acc = $class -> _copy($num);
1933 0         0 my $t = $class -> _one();
1934              
1935 0         0 my $expbin = $class -> _to_bin($exp);
1936 0         0 my $len = length($expbin);
1937              
1938 0         0 while ($len--) {
1939 0 0       0 if (substr($expbin, $len, 1) eq '1') { # if odd
1940 0         0 $t = $class -> _mul($t, $acc);
1941 0         0 $t = $class -> _mod($t, $mod);
1942             }
1943 0         0 $acc = $class -> _mul($acc, $acc);
1944 0         0 $acc = $class -> _mod($acc, $mod);
1945             }
1946 0         0 return $t;
1947             }
1948              
1949             sub _gcd {
1950             # Greatest common divisor.
1951              
1952 0     0   0 my ($class, $x, $y) = @_;
1953              
1954             # gcd(0, 0) = 0
1955             # gcd(0, a) = a, if a != 0
1956              
1957 0 0       0 if ($class -> _acmp($x, $y) == 0) {
1958 0         0 return $class -> _copy($x);
1959             }
1960              
1961 0 0       0 if ($class -> _is_zero($x)) {
1962 0 0       0 if ($class -> _is_zero($y)) {
1963 0         0 return $class -> _zero();
1964             } else {
1965 0         0 return $class -> _copy($y);
1966             }
1967             } else {
1968 0 0       0 if ($class -> _is_zero($y)) {
1969 0         0 return $class -> _copy($x);
1970             } else {
1971              
1972             # Until $y is zero ...
1973              
1974 0         0 $x = $class -> _copy($x);
1975 0         0 until ($class -> _is_zero($y)) {
1976              
1977             # Compute remainder.
1978              
1979 0         0 $x = $class -> _mod($x, $y);
1980              
1981             # Swap $x and $y.
1982              
1983 0         0 my $tmp = $x;
1984 0         0 $x = $class -> _copy($y);
1985 0         0 $y = $tmp;
1986             }
1987              
1988 0         0 return $x;
1989             }
1990             }
1991             }
1992              
1993             sub _lcm {
1994             # Least common multiple.
1995              
1996 14     14   38 my ($class, $x, $y) = @_;
1997              
1998             # lcm(0, x) = 0 for all x
1999              
2000 14 50 33     39 return $class -> _zero()
2001             if ($class -> _is_zero($x) ||
2002             $class -> _is_zero($y));
2003              
2004 14         40 my $gcd = $class -> _gcd($class -> _copy($x), $y);
2005 14         83 $x = $class -> _div($x, $gcd);
2006 14         63 $x = $class -> _mul($x, $y);
2007 14         70 return $x;
2008             }
2009              
2010             sub _lucas {
2011 0     0     my ($class, $n) = @_;
2012              
2013 0 0         $n = $class -> _num($n) if ref $n;
2014              
2015             # In list context, use lucas(n) = lucas(n-1) + lucas(n-2)
2016              
2017 0 0         if (wantarray) {
2018 0           my @y;
2019              
2020 0           push @y, $class -> _two();
2021 0 0         return @y if $n == 0;
2022              
2023 0           push @y, $class -> _one();
2024 0 0         return @y if $n == 1;
2025              
2026 0           for (my $i = 2 ; $i <= $n ; ++ $i) {
2027 0           $y[$i] = $class -> _add($class -> _copy($y[$i - 1]), $y[$i - 2]);
2028             }
2029              
2030 0           return @y;
2031             }
2032              
2033             # In scalar context use that lucas(n) = fib(n-1) + fib(n+1).
2034             #
2035             # Remember that _fib() behaves differently in scalar context and list
2036             # context, so we must add scalar() to get the desired behaviour.
2037              
2038 0 0         return $class -> _two() if $n == 0;
2039              
2040 0           return $class -> _add(scalar($class -> _fib($n - 1)),
2041             scalar($class -> _fib($n + 1)));
2042             }
2043              
2044             sub _fib {
2045 0     0     my ($class, $n) = @_;
2046              
2047 0 0         $n = $class -> _num($n) if ref $n;
2048              
2049             # In list context, use fib(n) = fib(n-1) + fib(n-2)
2050              
2051 0 0         if (wantarray) {
2052 0           my @y;
2053              
2054 0           push @y, $class -> _zero();
2055 0 0         return @y if $n == 0;
2056              
2057 0           push @y, $class -> _one();
2058 0 0         return @y if $n == 1;
2059              
2060 0           for (my $i = 2 ; $i <= $n ; ++ $i) {
2061 0           $y[$i] = $class -> _add($class -> _copy($y[$i - 1]), $y[$i - 2]);
2062             }
2063              
2064 0           return @y;
2065             }
2066              
2067             # In scalar context use a fast algorithm that is much faster than the
2068             # recursive algorith used in list context.
2069              
2070 0           my $cache = {};
2071 0           my $two = $class -> _two();
2072 0           my $fib;
2073              
2074             $fib = sub {
2075 0     0     my $n = shift;
2076 0 0         return $class -> _zero() if $n <= 0;
2077 0 0         return $class -> _one() if $n <= 2;
2078 0 0         return $cache -> {$n} if exists $cache -> {$n};
2079              
2080 0           my $k = int($n / 2);
2081 0           my $a = $fib -> ($k + 1);
2082 0           my $b = $fib -> ($k);
2083 0           my $y;
2084              
2085 0 0         if ($n % 2 == 1) {
2086             # a*a + b*b
2087 0           $y = $class -> _add($class -> _mul($class -> _copy($a), $a),
2088             $class -> _mul($class -> _copy($b), $b));
2089             } else {
2090             # (2*a - b)*b
2091 0           $y = $class -> _mul($class -> _sub($class -> _mul(
2092             $class -> _copy($two), $a), $b), $b);
2093             }
2094              
2095 0           $cache -> {$n} = $y;
2096 0           return $y;
2097 0           };
2098              
2099 0           return $fib -> ($n);
2100             }
2101              
2102             ##############################################################################
2103             ##############################################################################
2104              
2105             1;
2106              
2107             __END__