File Coverage

blib/lib/Math/BigInt/BitVect.pm
Criterion Covered Total %
statement 240 260 92.3
branch 97 126 76.9
condition 3 3 100.0
subroutine 44 49 89.8
pod 1 1 100.0
total 385 439 87.7


line stmt bran cond sub pod time code
1             package Math::BigInt::BitVect;
2              
3 8     8   914063 use 5.006;
  8         120  
4 8     8   45 use strict;
  8         16  
  8         186  
5 8     8   43 use warnings;
  8         29  
  8         292  
6              
7 8     8   6559 use Math::BigInt::Lib 1.999801;
  8         104622  
  8         44  
8              
9             our @ISA = qw< Math::BigInt::Lib >;
10              
11             our $VERSION = '1.21';
12              
13 8     8   4231 use Bit::Vector;
  8         9131  
  8         26610  
14              
15             ##############################################################################
16             # global constants, flags and accessory
17              
18             my $bits = 32; # make new numbers this wide
19             my $chunk = 32; # keep size a multiple of this
20              
21             # for is_* functions
22             my $zero = Bit::Vector->new_Dec($bits, 0);
23             my $one = Bit::Vector->new_Dec($bits, 1);
24             my $two = Bit::Vector->new_Dec($bits, 2);
25             my $ten = Bit::Vector->new_Dec($bits, 10);
26              
27 0     0 1 0 sub api_version { 2; }
28              
29       2     sub import { }
30              
31             sub __dump {
32 0     0   0 my ($class, $x) = @_;
33 0         0 my $str = $class -> _as_bin($x);
34              
35             # number of bits allocated
36              
37 0         0 my $nbits_alloc = $x -> Size();
38 0         0 my $imax = $x -> Max();
39              
40             # minimum number of bits needed
41              
42 0 0       0 my $nbits_min = $imax < 0 ? 1 : $imax + 2;
43              
44             # expected number of bits
45              
46 0         0 my $nbits_exp = $chunk * __ceil($nbits_min / $chunk);
47              
48 0         0 return "$str ($nbits_min/$nbits_exp/$nbits_alloc)";
49             }
50              
51             ##############################################################################
52             # create objects from various representations
53              
54             sub _new {
55 71440     71440   3583692 my ($class, $str) = @_;
56              
57             # $nbin is the maximum number of bits required to represent any $ndec digit
58             # number in base two. log(10)/log(2) = 3.32192809488736
59              
60 71440         116066 my $ndec = length($str);
61 71440         154639 my $nbin = 1 + __ceil(3.32192809488736 * $ndec);
62              
63 71440         139984 $nbin = $chunk * __ceil($nbin / $chunk); # chunked
64              
65 71440         842993 my $u = Bit::Vector->new_Dec($nbin, $str);
66 71440 100       178534 $class->__reduce($u) if $nbin > $bits;
67 71440         154774 $u;
68             }
69              
70             sub _from_hex {
71 319     319   4676 my ($class, $str) = @_;
72              
73 319         1096 $str =~ s/^0[xX]//;
74 319         667 my $bits = 1 + 4 * length($str);
75 319         657 $bits = $chunk * __ceil($bits / $chunk);
76 319         1086 my $x = Bit::Vector->new_Hex($bits, $str);
77 319         698 $class->__reduce($x);
78             }
79              
80             sub _from_bin {
81 66     66   898 my $str = $_[1];
82              
83 66         220 $str =~ s/^0[bB]//;
84 66         129 my $bits = 1 + length($str);
85 66         140 $bits = $chunk * __ceil($bits / $chunk);
86 66         274 Bit::Vector->new_Bin($bits, $str);
87             }
88              
89             sub _zero {
90 12314     12314   1120268 Bit::Vector->new_Dec($bits, 0);
91             }
92              
93             sub _one {
94 1842     1842   59406 Bit::Vector->new_Dec($bits, 1);
95             }
96              
97             sub _two {
98 302     302   2758 Bit::Vector->new_Dec($bits, 2);
99             }
100              
101             sub _ten {
102 0     0   0 Bit::Vector->new_Dec($bits, 10);
103             }
104              
105             sub _copy {
106 34717     34717   902345 $_[1]->Clone();
107             }
108              
109             ##############################################################################
110             # convert back to string and number
111              
112             sub _str {
113             # make string
114 53549     53549   109718830 my $x = $_[1]->to_Dec();
115 53549         138492 $x;
116             }
117              
118             sub _num {
119             # make a number
120 10388     10388   103666 0 + $_[1]->to_Dec();
121             }
122              
123             sub _as_hex {
124 70     70   924 my $x = lc $_[1]->to_Hex();
125 70         444 $x =~ s/^0*([\da-f])/0x$1/;
126 70         235 $x;
127             }
128              
129             sub _as_bin {
130 94     94   988 my $x = $_[1]->to_Bin();
131 94         683 $x =~ s/^0*(\d)/0b$1/;
132 94         320 $x;
133             }
134              
135             ##############################################################################
136             # actual math code
137              
138             sub _add {
139 24018     24018   294703 my ($class, $x, $y) = @_;
140              
141             # sizes must match!
142 24018         46118 my $xs = $x->Size();
143 24018         42594 my $ys = $y->Size();
144 24018         41481 my $ns = __max($xs, $ys) + 2; # 2 extra bits, to avoid overflow
145 24018         48579 $ns = $chunk * __ceil($ns / $chunk);
146 24018 50       77347 $x->Resize($ns) if $xs != $ns;
147 24018 50       65062 $y->Resize($ns) if $ys != $ns;
148 24018         71576 $x->add($x, $y, 0);
149              
150             # then reduce again
151 24018 50       70943 $class->__reduce($x) if $ns != $xs;
152 24018 50       63113 $class->__reduce($y) if $ns != $ys;
153              
154 24018         53354 $x;
155             }
156              
157             sub _sub {
158             # $x is always larger than $y! So overflow/underflow can not happen here
159 24595     24595   127038 my ($class, $x, $y, $z) = @_;
160              
161             # sizes must match!
162 24595         46831 my $xs = $x->Size();
163 24595         43404 my $ys = $y->Size();
164 24595         43186 my $ns = __max($xs, $ys); # no reserve, since no overflow
165 24595         49931 $ns = $chunk * __ceil($ns / $chunk);
166 24595 50       51462 $x->Resize($ns) if $xs != $ns;
167 24595 100       46379 $y->Resize($ns) if $ys != $ns;
168              
169 24595 100       40272 if ($z) {
170 2468         7624 $y->subtract($x, $y, 0);
171 2468         5738 $class->__reduce($y);
172 2468 50       4911 $class->__reduce($x) if $ns != $xs;
173             } else {
174 22127         69275 $x->subtract($x, $y, 0);
175 22127 100       43682 $class->__reduce($y) if $ns != $ys;
176 22127         42225 $class->__reduce($x);
177             }
178              
179 24595 100       66341 return $x unless $z;
180 2468         5351 $y;
181             }
182              
183             sub _mul {
184 22971     22971   318853 my ($class, $x, $y) = @_;
185              
186             # sizes must match!
187 22971         46383 my $xs = $x->Size();
188 22971         40245 my $ys = $y->Size();
189             # reserve some bits (and +2), so we never overflow
190 22971         36207 my $ns = $xs + $ys + 2; # 2^12 * 2^8 = 2^20 (so we take 22)
191 22971         44420 $ns = $chunk * __ceil($ns / $chunk);
192 22971 50       83172 $x->Resize($ns) if $xs != $ns;
193 22971 50       64101 $y->Resize($ns) if $ys != $ns;
194              
195             # then mul
196 22971         348643 $x->Multiply($x, $y);
197             # then reduce again
198 22971 50       67881 $class->__reduce($y) if $ns != $ys;
199 22971 50       65057 $class->__reduce($x) if $ns != $xs;
200 22971         44040 $x;
201             }
202              
203             sub _div {
204 19606     19606   79492 my ($class, $x, $y) = @_;
205              
206             # sizes must match!
207              
208 19606         39610 my $xs = $x->Max();
209 19606         36247 my $ys = $y->Max();
210              
211             # if $ys > $xs, quotient is zero
212              
213 19606 100 100     74496 if ($xs < 0 || $xs < $ys) {
214 497         1421 my $r = $x->Clone();
215 497         1484 $x = Bit::Vector->new_Hex($chunk, 0);
216 497 100       2710 return wantarray ? ($x, $r) : $x;
217             } else {
218 19109         36368 my $ns = $x->Size(); # common size
219 19109         32418 my $ys = $y->Size();
220 19109 100       61851 $y->Resize($ns) if $ys < $ns;
221 19109         53189 my $r = Bit::Vector->new_Hex($ns, 0);
222 19109         1541137 $x->Divide($x, $y, $r);
223 19109 100       56652 $class->__reduce($y) if $ys < $ns;
224 19109         45124 $class->__reduce($x);
225 19109 100       80427 return wantarray ? ($x, $class->__reduce($r)) : $x;
226             }
227             }
228              
229             sub _inc {
230 2255     2255   14709 my ($class, $x) = @_;
231              
232             # an overflow can occur if the leftmost bit and the rightmost bit are
233             # both 1 (we don't bother to look at the other bits)
234              
235 2255         4766 my $xs = $x->Size();
236 2255 50       8238 if ($x->bit_test($xs-2) & $x->bit_test(0)) {
237 0         0 $x->Resize($xs + $chunk); # make one bigger
238 0         0 $x->increment();
239 0         0 $class->__reduce($x); # in case no overflow occured
240             } else {
241 2255         5156 $x->increment(); # can't overflow, so no resize/reduce necc.
242             }
243 2255         4981 $x;
244             }
245              
246             sub _dec {
247             # input is >= 1
248 853     853   2998 my ($class, $x) = @_;
249              
250 853         2049 $x->decrement(); # will only get smaller, so reduce afterwards
251 853         1584 $class->__reduce($x);
252             }
253              
254             sub _and {
255             # bit-wise AND of two numbers
256 36     36   1710 my ($class, $x, $y) = @_;
257              
258             # sizes must match!
259 36         90 my $xs = $x->Size();
260 36         67 my $ys = $y->Size();
261 36         86 my $ns = __max($xs, $ys); # highest bits in $x, $y are zero
262 36         94 $ns = $chunk * __ceil($ns / $chunk);
263 36 50       97 $x->Resize($ns) if $xs != $ns;
264 36 100       84 $y->Resize($ns) if $ys != $ns;
265              
266 36         128 $x->And($x, $y);
267 36 50       74 $class->__reduce($y) if $ns != $xs;
268 36         93 $class->__reduce($x);
269 36         88 $x;
270             }
271              
272             sub _xor {
273             # bit-wise XOR of two numbers
274 53     53   1887 my ($class, $x, $y) = @_;
275              
276             # sizes must match!
277 53         123 my $xs = $x->Size();
278 53         105 my $ys = $y->Size();
279 53         107 my $ns = __max($xs, $ys); # highest bits in $x, $y are zero
280 53         144 $ns = $chunk * __ceil($ns / $chunk);
281 53 100       144 $x->Resize($ns) if $xs != $ns;
282 53 100       117 $y->Resize($ns) if $ys != $ns;
283              
284 53         175 $x->Xor($x, $y);
285 53 100       113 $class->__reduce($y) if $ns != $xs;
286 53         134 $class->__reduce($x);
287 53         122 $x;
288             }
289              
290             sub _or {
291             # bit-wise OR of two numbers
292 51     51   1588 my ($class, $x, $y) = @_;
293              
294             # sizes must match!
295 51         141 my $xs = $x->Size();
296 51         119 my $ys = $y->Size();
297 51         111 my $ns = __max($xs, $ys); # highest bits in $x, $y are zero
298 51         182 $ns = $chunk * __ceil($ns / $chunk);
299 51 100       180 $x->Resize($ns) if $xs != $ns;
300 51 100       135 $y->Resize($ns) if $ys != $ns;
301              
302 51         187 $x->Or($x, $y);
303 51 100       106 $class->__reduce($y) if $ns != $xs;
304 51 100       103 $class->__reduce($x) if $ns != $xs;
305 51         135 $x;
306             }
307              
308             sub _gcd {
309             # Greatest Common Divisor
310 33     33   478 my ($class, $x, $y) = @_;
311              
312             # Original, Bit::Vectors Euklid algorithmn
313             # sizes must match!
314 33         78 my $xs = $x->Size();
315 33         75 my $ys = $y->Size();
316 33         69 my $ns = __max($xs, $ys);
317 33 50       80 $x->Resize($ns) if $xs != $ns;
318 33 50       72 $y->Resize($ns) if $ys != $ns;
319 33         178 $x->GCD($x, $y);
320 33 50       68 $class->__reduce($y) if $ys != $ns;
321 33         85 $class->__reduce($x);
322 33         76 $x;
323             }
324              
325             ##############################################################################
326             # testing
327              
328             sub _acmp {
329 30708     30708   375329 my ($class, $x, $y) = @_;
330              
331 30708         60587 my $xm = $x->Size();
332 30708         57956 my $ym = $y->Size();
333 30708         47026 my $diff = ($xm - $ym);
334              
335 30708 100       61350 return $diff <=> 0 if $diff != 0;
336              
337             # used sizes are the same, so no need for Resizing/reducing
338 30342         92064 $x->Lexicompare($y);
339             }
340              
341             sub _len {
342             # return length, aka digits in decmial, costly!!
343 48205     48205   71164414 length($_[1]->to_Dec());
344             }
345              
346             sub _alen {
347 0     0   0 my $nb = $_[1] -> Max(); # index (zero-based)
348 0 0       0 return 1 if $nb < 0; # $nb is negative if $_[1] is zero
349 0         0 int(0.5 + 3.32192809488736 * ($nb + 1));
350             }
351              
352             sub _digit {
353             # return the nth digit, negative values count backward; this is costly!
354 27     27   179 my ($class, $x, $n) = @_;
355              
356 27         334 substr($x->to_Dec(), -($n+1), 1);
357             }
358              
359             sub _fac {
360             # factorial of $x
361 44     44   1410 my ($class, $x) = @_;
362              
363 44 100       121 if ($class->_is_zero($x)) {
364 1         5 $x = $class->_one(); # not $one since we need a copy/or new object!
365 1         5 return $x;
366             }
367 43         119 my $n = $class->_copy($x);
368 43         134 $x = $class->_one(); # not $one since we need a copy/or new object!
369 43         121 while (!$class->_is_one($n)) {
370 641         1513 $class->_mul($x, $n);
371 641         1116 $class->_dec($n);
372             }
373 43         237 $x; # no __reduce() since only getting bigger
374             }
375              
376             sub _pow {
377             # return power
378 24530     24530   51939 my ($class, $x, $y) = @_;
379              
380             # x**0 = 1
381              
382 24530 100       46456 return $class -> _one() if $class -> _is_zero($y);
383              
384             # 0**y = 0 if $y != 0 (y = 0 is taken care of above).
385              
386 23502 50       48399 return $class -> _zero() if $class -> _is_zero($x);
387              
388 23502         105872 my $ns = 1 + ($x -> Max() + 1) * $y -> to_Dec();
389 23502         53936 $ns = $chunk * __ceil($ns / $chunk);
390              
391 23502         64764 my $z = Bit::Vector -> new($ns);
392              
393 23502         824214 $z -> Power($x, $y);
394 23502         48935 return $class->__reduce($z);
395             }
396              
397             ###############################################################################
398             # shifting
399              
400             sub _rsft {
401 14272     14272   66852 my ($class, $x, $n, $b) = @_;
402              
403 14272 100       27069 if ($b == 2) {
404 15         50 $x->Move_Right($class->_num($n)); # must be scalar - ugh
405             } else {
406 14257 50       37496 $b = $class->_new($b) unless ref($b);
407 14257         35221 $x = $class->_div($x, $class->_pow($b, $n));
408             }
409 14272         42308 $class->__reduce($x);
410             }
411              
412             sub _lsft {
413 9944     9944   51432 my ($class, $x, $n, $b) = @_;
414              
415 9944 100       20274 if ($b == 2) {
416 8         27 $n = $class->_num($n); # need scalar for Resize/Move_Left - ugh
417 8         36 my $size = $x->Size() + 1 + $n; # y and one more
418 8         29 my $ns = (int($size / $chunk)+1)*$chunk;
419 8         27 $x->Resize($ns);
420 8         34 $x->Move_Left($n);
421 8         24 $class->__reduce($x); # to minimum size
422             } else {
423 9936         19652 $b = $class->_new($b);
424 9936         24324 $class->_mul($x, $class->_pow($b, $n));
425             }
426 9944         48142 return $x;
427             }
428              
429             ##############################################################################
430             # _is_* routines
431              
432             sub _is_zero {
433             # return true if arg is zero
434 174254     174254   3446621 my $x = $_[1];
435              
436 174254 100       476904 return $x -> is_empty() ? 1 : 0;
437             }
438              
439             sub _is_one {
440             # return true if arg is one
441 2951     2951   22618 my $x = $_[1];
442              
443 2951 100       8495 return 0 if $x->Size() != $bits; # if size mismatch
444 2596         7997 $x->equal($one);
445             }
446              
447             sub _is_two {
448             # return true if arg is two
449 56     56   2267 my $x = $_[1];
450              
451 56 100       193 return 0 if $x->Size() != $bits; # if size mismatch
452 48         160 $x->equal($two);
453             }
454              
455             sub _is_ten {
456             # return true if arg is ten
457 0     0   0 my $x = $_[1];
458              
459 0 0       0 return 0 if $x->Size() != $bits; # if size mismatch
460 0         0 $_[1]->equal($ten);
461             }
462              
463             sub _is_even {
464             # return true if arg is even
465              
466 23 100   23   1519 $_[1]->bit_test(0) ? 0 : 1;
467             }
468              
469             sub _is_odd {
470             # return true if arg is odd
471              
472 196 100   196   4454 $_[1]->bit_test(0) ? 1 : 0;
473             }
474              
475             ###############################################################################
476             # check routine to test internal state of corruptions
477              
478             sub _check {
479             # no checks yet, pull it out from the test suite
480 1830     1830   783681 my $x = $_[1];
481 1830 50       4880 return "Undefined" unless defined $x;
482 1830 100       4286 return "$x is not a reference to Bit::Vector" if ref($x) ne 'Bit::Vector';
483              
484 1829 50       7027 return "$x is negative" if $x->Sign() < 0;
485              
486             # Get the size.
487              
488 1829         4372 my $xs = $x -> Size();
489              
490             # The size must be a multiple of the chunk size.
491              
492 1829         5112 my $ns = $chunk * int($xs / $chunk);
493 1829 50       3833 if ($xs != $ns) {
494 0         0 return "Size($x) is $x bits, expected a multiple of $chunk.";
495             }
496              
497             # The size must not be larger than necessary.
498              
499 1829         4793 my $imax = $x -> Max(); # index of highest non-zero bit
500 1829 100       4409 my $nmin = $imax < 0 ? 1 : $imax + 2; # minimum number of bits required
501 1829         4321 $ns = $chunk * __ceil($nmin / $chunk); # minimum size in whole chunks
502 1829 50       3884 if ($xs != $ns) {
503 0         0 return "Size($x) is $xs bits, but only $ns bits are needed.";
504             }
505              
506 1829         3887 0;
507             }
508              
509             sub _mod {
510 766     766   6267 my ($class, $x, $y) = @_;
511              
512             # Get current sizes.
513              
514 766         1534 my $xs = $x -> Size();
515 766         1299 my $ys = $y -> Size();
516              
517             # Resize to a common size.
518              
519 766         1306 my $ns = __max($xs, $ys);
520 766 50       1571 $x -> Resize($ns) if $xs < $ns;
521 766 100       1774 $y -> Resize($ns) if $ys < $ns;
522 766         1998 my $quo = Bit::Vector -> new($ns);
523 766         1620 my $rem = Bit::Vector -> new($ns);
524              
525             # Get the quotient.
526              
527 766         19213 $quo -> Divide($x, $y, $rem);
528              
529             # Resize $y back to its original size, if necessary.
530              
531 766 100       1736 $y -> Resize($ys) if $ys < $ns;
532              
533 766         1366 $class -> __reduce($rem);
534             }
535              
536             # The following methods are not implemented (yet):
537              
538             #sub _1ex { }
539              
540             #sub _as_bytes { }
541              
542             #sub _as_oct { }
543              
544             #sub _from_bytes { }
545              
546             #sub _from_oct { }
547              
548             #sub _lcm { }
549              
550             #sub _log_int { }
551              
552             #sub _modinv { }
553              
554             #sub _modpow { }
555              
556             #sub _nok { }
557              
558             #sub _root { }
559              
560             #sub _sqrt { }
561              
562             #sub _zeros { }
563              
564             sub __reduce {
565             # internal reduction to make minimum size
566 209681     209681   340274 my ($class, $x) = @_;
567              
568 209681         371638 my $bits_allocated = $x->Size();
569 209681 100       399991 return $x if $bits_allocated <= $chunk;
570              
571             # The number of bits we use is always a positive multiple of $chunk. Add
572             # two extra bits to $imax; one because $imax is zero-based, and one to
573             # avoid that the highest bit is one, which signifies a negative number.
574              
575 174259         312377 my $imax = $x->Max();
576 174259 100       302021 my $bits_needed = $imax < 0 ? 1 : 2 + $imax;
577 174259         297373 $bits_needed = $chunk * __ceil($bits_needed / $chunk);
578              
579 174259 100       335942 if ($bits_allocated > $bits_needed) {
580 139602         256603 $x->Resize($bits_needed);
581             }
582              
583 174259         306757 $x;
584             }
585              
586             ###############################################################################
587             # helper/utility functions
588              
589             # maximum of 2 values
590              
591             sub __max {
592 49552     49552   78561 my ($m, $n) = @_;
593 49552 100       101301 $m > $n ? $m : $n;
594             }
595              
596             # ceiling function
597              
598             sub __ceil {
599 414579     414579   562088 my $x = shift;
600 414579         597946 my $ix = int $x;
601 414579 100       803484 ($ix >= $x) ? $ix : $ix + 1;
602             }
603              
604             1;
605              
606             __END__