File Coverage

blib/lib/Math/BigInt/BitVect.pm
Criterion Covered Total %
statement 238 260 91.5
branch 97 126 76.9
condition 3 3 100.0
subroutine 44 49 89.8
pod 1 1 100.0
total 383 439 87.2


line stmt bran cond sub pod time code
1             package Math::BigInt::BitVect;
2              
3 8     8   1399455 use 5.006;
  8         30  
4 8     8   47 use strict;
  8         17  
  8         238  
5 8     8   37 use warnings;
  8         32  
  8         564  
6              
7 8     8   6632 use Math::BigInt::Lib 1.999801;
  8         127445  
  8         57  
8              
9             our @ISA = qw< Math::BigInt::Lib >;
10              
11             our $VERSION = '1.26';
12              
13 8     8   4757 use Bit::Vector;
  8         22372  
  8         30677  
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 73127     73127   7180783 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 73127         130619 my $ndec = length($str);
61 73127         168465 my $nbin = 1 + __ceil(3.32192809488736 * $ndec);
62              
63 73127         142883 $nbin = $chunk * __ceil($nbin / $chunk); # chunked
64              
65 73127         661957 my $u = Bit::Vector->new_Dec($nbin, $str);
66 73127 100       193503 $class->__reduce($u) if $nbin > $bits;
67 73127         171819 $u;
68             }
69              
70             sub _from_hex {
71 319     319   5203 my ($class, $str) = @_;
72              
73 319         1272 $str =~ s/^0[xX]//;
74 319         666 my $bits = 1 + 4 * length($str);
75 319         740 $bits = $chunk * __ceil($bits / $chunk);
76 319         1264 my $x = Bit::Vector->new_Hex($bits, $str);
77 319         882 $class->__reduce($x);
78             }
79              
80             sub _from_bin {
81 66     66   1100 my $str = $_[1];
82              
83 66         269 $str =~ s/^0[bB]//;
84 66         129 my $bits = 1 + length($str);
85 66         151 $bits = $chunk * __ceil($bits / $chunk);
86 66         317 Bit::Vector->new_Bin($bits, $str);
87             }
88              
89             sub _zero {
90 11288     11288   1599677 Bit::Vector->new_Dec($bits, 0);
91             }
92              
93             sub _one {
94 1175     1175   90266 Bit::Vector->new_Dec($bits, 1);
95             }
96              
97             sub _two {
98 227     227   2622 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 36197     36197   1359407 $_[1]->Clone();
107             }
108              
109             ##############################################################################
110             # convert back to string and number
111              
112             sub _str {
113             # make string
114 54067     54067   68762923 my $x = $_[1]->to_Dec();
115 54067         156794 $x;
116             }
117              
118             sub _num {
119             # make a number
120 10286     10286   124392 0 + $_[1]->to_Dec();
121             }
122              
123             sub _as_hex {
124 70     70   1058 my $x = lc $_[1]->to_Hex();
125 70         507 $x =~ s/^0*([\da-f])/0x$1/;
126 70         208 $x;
127             }
128              
129             sub _as_bin {
130 12     12   524 my $x = $_[1]->to_Bin();
131 12         91 $x =~ s/^0*(\d)/0b$1/;
132 12         38 $x;
133             }
134              
135             ##############################################################################
136             # actual math code
137              
138             sub _add {
139 24506     24506   329780 my ($class, $x, $y) = @_;
140              
141             # sizes must match!
142 24506         50207 my $xs = $x->Size();
143 24506         44879 my $ys = $y->Size();
144 24506         43896 my $ns = __max($xs, $ys) + 2; # 2 extra bits, to avoid overflow
145 24506         48795 $ns = $chunk * __ceil($ns / $chunk);
146 24506 50       82815 $x->Resize($ns) if $xs != $ns;
147 24506 50       72112 $y->Resize($ns) if $ys != $ns;
148 24506         79992 $x->add($x, $y, 0);
149              
150             # then reduce again
151 24506 50       75136 $class->__reduce($x) if $ns != $xs;
152 24506 50       69927 $class->__reduce($y) if $ns != $ys;
153              
154 24506         57691 $x;
155             }
156              
157             sub _sub {
158             # $x is always larger than $y! So overflow/underflow can not happen here
159 25014     25014   140325 my ($class, $x, $y, $z) = @_;
160              
161             # sizes must match!
162 25014         49721 my $xs = $x->Size();
163 25014         47049 my $ys = $y->Size();
164 25014         46438 my $ns = __max($xs, $ys); # no reserve, since no overflow
165 25014         52357 $ns = $chunk * __ceil($ns / $chunk);
166 25014 50       57543 $x->Resize($ns) if $xs != $ns;
167 25014 100       49363 $y->Resize($ns) if $ys != $ns;
168              
169 25014 100       46121 if ($z) {
170 2507         8832 $y->subtract($x, $y, 0);
171 2507         6831 $class->__reduce($y);
172 2507 50       5530 $class->__reduce($x) if $ns != $xs;
173             } else {
174 22507         77676 $x->subtract($x, $y, 0);
175 22507 100       46373 $class->__reduce($y) if $ns != $ys;
176 22507         47743 $class->__reduce($x);
177             }
178              
179 25014 100       76326 return $x unless $z;
180 2507         6040 $y;
181             }
182              
183             sub _mul {
184 21750     21750   738340 my ($class, $x, $y) = @_;
185              
186             # sizes must match!
187 21750         49393 my $xs = $x->Size();
188 21750         41247 my $ys = $y->Size();
189             # reserve some bits (and +2), so we never overflow
190 21750         34404 my $ns = $xs + $ys + 2; # 2^12 * 2^8 = 2^20 (so we take 22)
191 21750         45641 $ns = $chunk * __ceil($ns / $chunk);
192 21750 50       83632 $x->Resize($ns) if $xs != $ns;
193 21750 50       65282 $y->Resize($ns) if $ys != $ns;
194              
195             # then mul
196 21750         198299 $x->Multiply($x, $y);
197             # then reduce again
198 21750 50       70324 $class->__reduce($y) if $ns != $ys;
199 21750 50       66244 $class->__reduce($x) if $ns != $xs;
200 21750         47426 $x;
201             }
202              
203             sub _div {
204 20059     20059   86177 my ($class, $x, $y) = @_;
205              
206             # sizes must match!
207              
208 20059         42259 my $xs = $x->Max();
209 20059         38535 my $ys = $y->Max();
210              
211             # if $ys > $xs, quotient is zero
212              
213 20059 100 100     78845 if ($xs < 0 || $xs < $ys) {
214 451         1427 my $r = $x->Clone();
215 451         1658 $x = Bit::Vector->new_Hex($chunk, 0);
216 451 100       2714 return wantarray ? ($x, $r) : $x;
217             } else {
218 19608         38591 my $ns = $x->Size(); # common size
219 19608         36627 my $ys = $y->Size();
220 19608 100       64150 $y->Resize($ns) if $ys < $ns;
221 19608         65119 my $r = Bit::Vector->new_Hex($ns, 0);
222 19608         1125552 $x->Divide($x, $y, $r);
223 19608 100       65200 $class->__reduce($y) if $ys < $ns;
224 19608         46268 $class->__reduce($x);
225 19608 100       97375 return wantarray ? ($x, $class->__reduce($r)) : $x;
226             }
227             }
228              
229             sub _inc {
230 2424     2424   18036 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 2424         5992 my $xs = $x->Size();
236 2424 50       11824 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 2424         5832 $x->increment(); # can't overflow, so no resize/reduce necc.
242             }
243 2424         5960 $x;
244             }
245              
246             sub _dec {
247             # input is >= 1
248 838     838   3193 my ($class, $x) = @_;
249              
250 838         2372 $x->decrement(); # will only get smaller, so reduce afterwards
251 838         1848 $class->__reduce($x);
252             }
253              
254             sub _and {
255             # bit-wise AND of two numbers
256 36     36   1685 my ($class, $x, $y) = @_;
257              
258             # sizes must match!
259 36         95 my $xs = $x->Size();
260 36         76 my $ys = $y->Size();
261 36         95 my $ns = __max($xs, $ys); # highest bits in $x, $y are zero
262 36         94 $ns = $chunk * __ceil($ns / $chunk);
263 36 50       104 $x->Resize($ns) if $xs != $ns;
264 36 100       97 $y->Resize($ns) if $ys != $ns;
265              
266 36         168 $x->And($x, $y);
267 36 50       75 $class->__reduce($y) if $ns != $xs;
268 36         103 $class->__reduce($x);
269 36         92 $x;
270             }
271              
272             sub _xor {
273             # bit-wise XOR of two numbers
274 53     53   2434 my ($class, $x, $y) = @_;
275              
276             # sizes must match!
277 53         161 my $xs = $x->Size();
278 53         120 my $ys = $y->Size();
279 53         152 my $ns = __max($xs, $ys); # highest bits in $x, $y are zero
280 53         180 $ns = $chunk * __ceil($ns / $chunk);
281 53 100       161 $x->Resize($ns) if $xs != $ns;
282 53 100       127 $y->Resize($ns) if $ys != $ns;
283              
284 53         221 $x->Xor($x, $y);
285 53 100       126 $class->__reduce($y) if $ns != $xs;
286 53         176 $class->__reduce($x);
287 53         159 $x;
288             }
289              
290             sub _or {
291             # bit-wise OR of two numbers
292 51     51   2623 my ($class, $x, $y) = @_;
293              
294             # sizes must match!
295 51         173 my $xs = $x->Size();
296 51         125 my $ys = $y->Size();
297 51         149 my $ns = __max($xs, $ys); # highest bits in $x, $y are zero
298 51         157 $ns = $chunk * __ceil($ns / $chunk);
299 51 100       172 $x->Resize($ns) if $xs != $ns;
300 51 100       145 $y->Resize($ns) if $ys != $ns;
301              
302 51         235 $x->Or($x, $y);
303 51 100       144 $class->__reduce($y) if $ns != $xs;
304 51 100       127 $class->__reduce($x) if $ns != $xs;
305 51         181 $x;
306             }
307              
308             sub _gcd {
309             # Greatest Common Divisor
310 33     33   279 my ($class, $x, $y) = @_;
311              
312             # Original, Bit::Vectors Euklid algorithmn
313             # sizes must match!
314 33         127 my $xs = $x->Size();
315 33         58 my $ys = $y->Size();
316 33         82 my $ns = __max($xs, $ys);
317 33 50       75 $x->Resize($ns) if $xs != $ns;
318 33 50       77 $y->Resize($ns) if $ys != $ns;
319 33         192 $x->GCD($x, $y);
320 33 50       64 $class->__reduce($y) if $ys != $ns;
321 33         112 $class->__reduce($x);
322 33         77 $x;
323             }
324              
325             ##############################################################################
326             # testing
327              
328             sub _acmp {
329 31514     31514   441878 my ($class, $x, $y) = @_;
330              
331 31514         66003 my $xm = $x->Size();
332 31514         56668 my $ym = $y->Size();
333 31514         47893 my $diff = ($xm - $ym);
334              
335 31514 100       70562 return $diff <=> 0 if $diff != 0;
336              
337             # used sizes are the same, so no need for Resizing/reducing
338 31099         106948 $x->Lexicompare($y);
339             }
340              
341             sub _len {
342             # return length, aka digits in decmial, costly!!
343 49233     49233   47304450 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   224 my ($class, $x, $n) = @_;
355              
356 27         457 substr($x->to_Dec(), -($n+1), 1);
357             }
358              
359             sub _fac {
360             # factorial of $x
361 42     42   366 my ($class, $x) = @_;
362              
363 42 50       126 if ($class->_is_zero($x)) {
364 0         0 $x = $class->_one(); # not $one since we need a copy/or new object!
365 0         0 return $x;
366             }
367 42         128 my $n = $class->_copy($x);
368 42         121 $x = $class->_one(); # not $one since we need a copy/or new object!
369 42         122 while (!$class->_is_one($n)) {
370 641         1964 $class->_mul($x, $n);
371 641         1620 $class->_dec($n);
372             }
373 42         338 $x; # no __reduce() since only getting bigger
374             }
375              
376             sub _pow {
377             # return power
378 24181     24181   59793 my ($class, $x, $y) = @_;
379              
380             # x**0 = 1
381              
382 24181 100       49162 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 23853 50       48572 return $class -> _zero() if $class -> _is_zero($x);
387              
388 23853         120901 my $ns = 1 + ($x -> Max() + 1) * $y -> to_Dec();
389 23853         54328 $ns = $chunk * __ceil($ns / $chunk);
390              
391 23853         69579 my $z = Bit::Vector -> new($ns);
392              
393 23853         692155 $z -> Power($x, $y);
394 23853         52826 return $class->__reduce($z);
395             }
396              
397             ###############################################################################
398             # shifting
399              
400             sub _rsft {
401 14692     14692   78758 my ($class, $x, $n, $b) = @_;
402              
403 14692 100       28168 if ($b == 2) {
404 15         43 $x->Move_Right($class->_num($n)); # must be scalar - ugh
405             } else {
406 14677 50       40501 $b = $class->_new($b) unless ref($b);
407 14677         39356 $x = $class->_div($x, $class->_pow($b, $n));
408             }
409 14692         44528 $class->__reduce($x);
410             }
411              
412             sub _lsft {
413 9190     9190   45901 my ($class, $x, $n, $b) = @_;
414              
415 9190 100       17668 if ($b == 2) {
416 18         46 $n = $class->_num($n); # need scalar for Resize/Move_Left - ugh
417 18         51 my $size = $x->Size() + 1 + $n; # y and one more
418 18         77 my $ns = (int($size / $chunk)+1)*$chunk;
419 18         57 $x->Resize($ns);
420 18         64 $x->Move_Left($n);
421 18         44 $class->__reduce($x); # to minimum size
422             } else {
423 9172         20146 $b = $class->_new($b);
424 9172         24746 $class->_mul($x, $class->_pow($b, $n));
425             }
426 9190         58992 return $x;
427             }
428              
429             ##############################################################################
430             # _is_* routines
431              
432             sub _is_zero {
433             # return true if arg is zero
434 165865     165865   4941552 my $x = $_[1];
435              
436 165865 100       527634 return $x -> is_empty() ? 1 : 0;
437             }
438              
439             sub _is_one {
440             # return true if arg is one
441 2213     2213   24881 my $x = $_[1];
442              
443 2213 100       7089 return 0 if $x->Size() != $bits; # if size mismatch
444 2108         7019 $x->equal($one);
445             }
446              
447             sub _is_two {
448             # return true if arg is two
449 56     56   5018 my $x = $_[1];
450              
451 56 100       293 return 0 if $x->Size() != $bits; # if size mismatch
452 48         196 $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   2068 $_[1]->bit_test(0) ? 0 : 1;
467             }
468              
469             sub _is_odd {
470             # return true if arg is odd
471              
472 207 100   207   6022 $_[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 1838     1838   957949 my $x = $_[1];
481 1838 50       5919 return "Undefined" unless defined $x;
482 1838 100       5639 return "$x is not a reference to Bit::Vector" if ref($x) ne 'Bit::Vector';
483              
484 1837 50       8347 return "$x is negative" if $x->Sign() < 0;
485              
486             # Get the size.
487              
488 1837         5342 my $xs = $x -> Size();
489              
490             # The size must be a multiple of the chunk size.
491              
492 1837         5287 my $ns = $chunk * int($xs / $chunk);
493 1837 50       4575 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 1837         5488 my $imax = $x -> Max(); # index of highest non-zero bit
500 1837 100       4818 my $nmin = $imax < 0 ? 1 : $imax + 2; # minimum number of bits required
501 1837         4879 $ns = $chunk * __ceil($nmin / $chunk); # minimum size in whole chunks
502 1837 50       4817 if ($xs != $ns) {
503 0         0 return "Size($x) is $xs bits, but only $ns bits are needed.";
504             }
505              
506 1837         4630 0;
507             }
508              
509             sub _mod {
510 879     879   7838 my ($class, $x, $y) = @_;
511              
512             # Get current sizes.
513              
514 879         2253 my $xs = $x -> Size();
515 879         2207 my $ys = $y -> Size();
516              
517             # Resize to a common size.
518              
519 879         1895 my $ns = __max($xs, $ys);
520 879 100       2057 $x -> Resize($ns) if $xs < $ns;
521 879 100       2466 $y -> Resize($ns) if $ys < $ns;
522 879         2915 my $quo = Bit::Vector -> new($ns);
523 879         2197 my $rem = Bit::Vector -> new($ns);
524              
525             # Get the quotient.
526              
527 879         22457 $quo -> Divide($x, $y, $rem);
528              
529             # Resize $y back to its original size, if necessary.
530              
531 879 100       2465 $y -> Resize($ys) if $ys < $ns;
532              
533 879         2093 $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 210708     210708   365630 my ($class, $x) = @_;
567              
568 210708         403121 my $bits_allocated = $x->Size();
569 210708 100       423016 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 174566         345929 my $imax = $x->Max();
576 174566 100       304731 my $bits_needed = $imax < 0 ? 1 : 2 + $imax;
577 174566         307972 $bits_needed = $chunk * __ceil($bits_needed / $chunk);
578              
579 174566 100       330434 if ($bits_allocated > $bits_needed) {
580 138634         288874 $x->Resize($bits_needed);
581             }
582              
583 174566         342861 $x;
584             }
585              
586             ###############################################################################
587             # helper/utility functions
588              
589             # maximum of 2 values
590              
591             sub __max {
592 50572     50572   87550 my ($m, $n) = @_;
593 50572 100       107078 $m > $n ? $m : $n;
594             }
595              
596             # ceiling function
597              
598             sub __ceil {
599 418305     418305   588990 my $x = shift;
600 418305         613907 my $ix = int $x;
601 418305 100       863915 ($ix >= $x) ? $ix : $ix + 1;
602             }
603              
604             1;
605              
606             __END__