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   747668 use 5.006;
  8         99  
4 8     8   38 use strict;
  8         13  
  8         171  
5 8     8   36 use warnings;
  8         12  
  8         275  
6              
7 8     8   4123 use Math::BigInt::Lib 1.999801;
  8         70141  
  8         41  
8              
9             our @ISA = qw< Math::BigInt::Lib >;
10              
11             our $VERSION = '1.19';
12              
13 8     8   3491 use Bit::Vector;
  8         7105  
  8         20975  
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 71011     71011   2817086 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 71011         92623 my $ndec = length($str);
61 71011         124278 my $nbin = 1 + __ceil(3.32192809488736 * $ndec);
62              
63 71011         113839 $nbin = $chunk * __ceil($nbin / $chunk); # chunked
64              
65 71011         675882 my $u = Bit::Vector->new_Dec($nbin, $str);
66 71011 100       143154 $class->__reduce($u) if $nbin > $bits;
67 71011         123899 $u;
68             }
69              
70             sub _from_hex {
71 319     319   3549 my ($class, $str) = @_;
72              
73 319         924 $str =~ s/^0[xX]//;
74 319         583 my $bits = 1 + 4 * length($str);
75 319         582 $bits = $chunk * __ceil($bits / $chunk);
76 319         873 my $x = Bit::Vector->new_Hex($bits, $str);
77 319         550 $class->__reduce($x);
78             }
79              
80             sub _from_bin {
81 50     50   549 my $str = $_[1];
82              
83 50         145 $str =~ s/^0[bB]//;
84 50         88 my $bits = 1 + length($str);
85 50         87 $bits = $chunk * __ceil($bits / $chunk);
86 50         159 Bit::Vector->new_Bin($bits, $str);
87             }
88              
89             sub _zero {
90 13082     13082   901189 Bit::Vector->new_Dec($bits, 0);
91             }
92              
93             sub _one {
94 1829     1829   45170 Bit::Vector->new_Dec($bits, 1);
95             }
96              
97             sub _two {
98 294     294   2080 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 30976     30976   676696 $_[1]->Clone();
107             }
108              
109             ##############################################################################
110             # convert back to string and number
111              
112             sub _str {
113             # make string
114 52884     52884   89447915 my $x = $_[1]->to_Dec();
115 52884         111158 $x;
116             }
117              
118             sub _num {
119             # make a number
120 10750     10750   85436 0 + $_[1]->to_Dec();
121             }
122              
123             sub _as_hex {
124 70     70   768 my $x = lc $_[1]->to_Hex();
125 70         336 $x =~ s/^0*([\da-f])/0x$1/;
126 70         178 $x;
127             }
128              
129             sub _as_bin {
130 95     95   830 my $x = $_[1]->to_Bin();
131 95         560 $x =~ s/^0*(\d)/0b$1/;
132 95         255 $x;
133             }
134              
135             ##############################################################################
136             # actual math code
137              
138             sub _add {
139 23820     23820   241835 my ($class, $x, $y) = @_;
140              
141             # sizes must match!
142 23820         38168 my $xs = $x->Size();
143 23820         33908 my $ys = $y->Size();
144 23820         33502 my $ns = __max($xs, $ys) + 2; # 2 extra bits, to avoid overflow
145 23820         38895 $ns = $chunk * __ceil($ns / $chunk);
146 23820 50       62100 $x->Resize($ns) if $xs != $ns;
147 23820 50       51568 $y->Resize($ns) if $ys != $ns;
148 23820         58125 $x->add($x, $y, 0);
149              
150             # then reduce again
151 23820 50       56291 $class->__reduce($x) if $ns != $xs;
152 23820 50       52102 $class->__reduce($y) if $ns != $ys;
153              
154 23820         42436 $x;
155             }
156              
157             sub _sub {
158             # $x is always larger than $y! So overflow/underflow can not happen here
159 24361     24361   104991 my ($class, $x, $y, $z) = @_;
160              
161             # sizes must match!
162 24361         38738 my $xs = $x->Size();
163 24361         36470 my $ys = $y->Size();
164 24361         37701 my $ns = __max($xs, $ys); # no reserve, since no overflow
165 24361         41166 $ns = $chunk * __ceil($ns / $chunk);
166 24361 50       43459 $x->Resize($ns) if $xs != $ns;
167 24361 100       37950 $y->Resize($ns) if $ys != $ns;
168              
169 24361 100       34308 if ($z) {
170 2736         7004 $y->subtract($x, $y, 0);
171 2736         5835 $class->__reduce($y);
172 2736 50       4462 $class->__reduce($x) if $ns != $xs;
173             } else {
174 21625         56266 $x->subtract($x, $y, 0);
175 21625 100       34118 $class->__reduce($y) if $ns != $ys;
176 21625         34849 $class->__reduce($x);
177             }
178              
179 24361 100       54038 return $x unless $z;
180 2736         5056 $y;
181             }
182              
183             sub _mul {
184 22649     22649   289193 my ($class, $x, $y) = @_;
185              
186             # sizes must match!
187 22649         37509 my $xs = $x->Size();
188 22649         31645 my $ys = $y->Size();
189             # reserve some bits (and +2), so we never overflow
190 22649         28527 my $ns = $xs + $ys + 2; # 2^12 * 2^8 = 2^20 (so we take 22)
191 22649         36133 $ns = $chunk * __ceil($ns / $chunk);
192 22649 50       68037 $x->Resize($ns) if $xs != $ns;
193 22649 50       53393 $y->Resize($ns) if $ys != $ns;
194              
195             # then mul
196 22649         286673 $x->Multiply($x, $y);
197             # then reduce again
198 22649 50       54759 $class->__reduce($y) if $ns != $ys;
199 22649 50       52236 $class->__reduce($x) if $ns != $xs;
200 22649         36057 $x;
201             }
202              
203             sub _div {
204 19540     19540   64220 my ($class, $x, $y) = @_;
205              
206             # sizes must match!
207              
208 19540         32787 my $xs = $x->Max();
209 19540         28567 my $ys = $y->Max();
210              
211             # if $ys > $xs, quotient is zero
212              
213 19540 100 100     60648 if ($xs < 0 || $xs < $ys) {
214 495         1170 my $r = $x->Clone();
215 495         1220 $x = Bit::Vector->new_Hex($chunk, 0);
216 495 100       2148 return wantarray ? ($x, $r) : $x;
217             } else {
218 19045         30641 my $ns = $x->Size(); # common size
219 19045         27117 my $ys = $y->Size();
220 19045 100       48814 $y->Resize($ns) if $ys < $ns;
221 19045         43248 my $r = Bit::Vector->new_Hex($ns, 0);
222 19045         1253291 $x->Divide($x, $y, $r);
223 19045 100       46127 $class->__reduce($y) if $ys < $ns;
224 19045         35812 $class->__reduce($x);
225 19045 100       65049 return wantarray ? ($x, $class->__reduce($r)) : $x;
226             }
227             }
228              
229             sub _inc {
230 2444     2444   14180 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 2444         4490 my $xs = $x->Size();
236 2444 50       8746 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 2444         4880 $x->increment(); # can't overflow, so no resize/reduce necc.
242             }
243 2444         4919 $x;
244             }
245              
246             sub _dec {
247             # input is >= 1
248 836     836   2071 my ($class, $x) = @_;
249              
250 836         1659 $x->decrement(); # will only get smaller, so reduce afterwards
251 836         1323 $class->__reduce($x);
252             }
253              
254             sub _and {
255             # bit-wise AND of two numbers
256 36     36   1105 my ($class, $x, $y) = @_;
257              
258             # sizes must match!
259 36         73 my $xs = $x->Size();
260 36         67 my $ys = $y->Size();
261 36         62 my $ns = __max($xs, $ys); # highest bits in $x, $y are zero
262 36         89 $ns = $chunk * __ceil($ns / $chunk);
263 36 50       78 $x->Resize($ns) if $xs != $ns;
264 36 100       79 $y->Resize($ns) if $ys != $ns;
265              
266 36         107 $x->And($x, $y);
267 36 50       77 $class->__reduce($y) if $ns != $xs;
268 36         76 $class->__reduce($x);
269 36         71 $x;
270             }
271              
272             sub _xor {
273             # bit-wise XOR of two numbers
274 53     53   1414 my ($class, $x, $y) = @_;
275              
276             # sizes must match!
277 53         109 my $xs = $x->Size();
278 53         90 my $ys = $y->Size();
279 53         90 my $ns = __max($xs, $ys); # highest bits in $x, $y are zero
280 53         105 $ns = $chunk * __ceil($ns / $chunk);
281 53 100       124 $x->Resize($ns) if $xs != $ns;
282 53 100       93 $y->Resize($ns) if $ys != $ns;
283              
284 53         187 $x->Xor($x, $y);
285 53 100       96 $class->__reduce($y) if $ns != $xs;
286 53         106 $class->__reduce($x);
287 53         108 $x;
288             }
289              
290             sub _or {
291             # bit-wise OR of two numbers
292 51     51   1287 my ($class, $x, $y) = @_;
293              
294             # sizes must match!
295 51         115 my $xs = $x->Size();
296 51         94 my $ys = $y->Size();
297 51         94 my $ns = __max($xs, $ys); # highest bits in $x, $y are zero
298 51         114 $ns = $chunk * __ceil($ns / $chunk);
299 51 100       109 $x->Resize($ns) if $xs != $ns;
300 51 100       112 $y->Resize($ns) if $ys != $ns;
301              
302 51         170 $x->Or($x, $y);
303 51 100       87 $class->__reduce($y) if $ns != $xs;
304 51 100       91 $class->__reduce($x) if $ns != $xs;
305 51         108 $x;
306             }
307              
308             sub _gcd {
309             # Greatest Common Divisor
310 33     33   449 my ($class, $x, $y) = @_;
311              
312             # Original, Bit::Vectors Euklid algorithmn
313             # sizes must match!
314 33         64 my $xs = $x->Size();
315 33         67 my $ys = $y->Size();
316 33         53 my $ns = __max($xs, $ys);
317 33 50       68 $x->Resize($ns) if $xs != $ns;
318 33 50       54 $y->Resize($ns) if $ys != $ns;
319 33         134 $x->GCD($x, $y);
320 33 50       60 $class->__reduce($y) if $ys != $ns;
321 33         69 $class->__reduce($x);
322 33         63 $x;
323             }
324              
325             ##############################################################################
326             # testing
327              
328             sub _acmp {
329 28609     28609   287493 my ($class, $x, $y) = @_;
330              
331 28609         45438 my $xm = $x->Size();
332 28609         41989 my $ym = $y->Size();
333 28609         35844 my $diff = ($xm - $ym);
334              
335 28609 100       46488 return $diff <=> 0 if $diff != 0;
336              
337             # used sizes are the same, so no need for Resizing/reducing
338 28262         70214 $x->Lexicompare($y);
339             }
340              
341             sub _len {
342             # return length, aka digits in decmial, costly!!
343 47688     47688   58149965 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   136 my ($class, $x, $n) = @_;
355              
356 27         234 substr($x->to_Dec(), -($n+1), 1);
357             }
358              
359             sub _fac {
360             # factorial of $x
361 44     44   1047 my ($class, $x) = @_;
362              
363 44 100       97 if ($class->_is_zero($x)) {
364 1         3 $x = $class->_one(); # not $one since we need a copy/or new object!
365 1         3 return $x;
366             }
367 43         110 my $n = $class->_copy($x);
368 43         121 $x = $class->_one(); # not $one since we need a copy/or new object!
369 43         97 while (!$class->_is_one($n)) {
370 641         1252 $class->_mul($x, $n);
371 641         878 $class->_dec($n);
372             }
373 43         193 $x; # no __reduce() since only getting bigger
374             }
375              
376             sub _pow {
377             # return power
378 24180     24180   40022 my ($class, $x, $y) = @_;
379              
380             # x**0 = 1
381              
382 24180 100       37087 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 23168 50       36908 return $class -> _zero() if $class -> _is_zero($x);
387              
388 23168         86235 my $ns = 1 + ($x -> Max() + 1) * $y -> to_Dec();
389 23168         43514 $ns = $chunk * __ceil($ns / $chunk);
390              
391 23168         50488 my $z = Bit::Vector -> new($ns);
392              
393 23168         672462 $z -> Power($x, $y);
394 23168         40009 return $class->__reduce($z);
395             }
396              
397             ###############################################################################
398             # shifting
399              
400             sub _rsft {
401 14107     14107   53481 my ($class, $x, $n, $b) = @_;
402              
403 14107 100       23058 if ($b == 2) {
404 29         55 $x->Move_Right($class->_num($n)); # must be scalar - ugh
405             } else {
406 14078 50       29992 $b = $class->_new($b) unless ref($b);
407 14078         27319 $x = $class->_div($x, $class->_pow($b, $n));
408             }
409 14107         33626 $class->__reduce($x);
410             }
411              
412             sub _lsft {
413 9802     9802   40135 my ($class, $x, $n, $b) = @_;
414              
415 9802 100       16455 if ($b == 2) {
416 15         46 $n = $class->_num($n); # need scalar for Resize/Move_Left - ugh
417 15         41 my $size = $x->Size() + 1 + $n; # y and one more
418 15         31 my $ns = (int($size / $chunk)+1)*$chunk;
419 15         36 $x->Resize($ns);
420 15         43 $x->Move_Left($n);
421 15         32 $class->__reduce($x); # to minimum size
422             } else {
423 9787         15997 $b = $class->_new($b);
424 9787         19357 $class->_mul($x, $class->_pow($b, $n));
425             }
426 9802         39371 return $x;
427             }
428              
429             ##############################################################################
430             # _is_* routines
431              
432             sub _is_zero {
433             # return true if arg is zero
434 173683     173683   2861482 my $x = $_[1];
435              
436 173683 100       396601 return $x -> is_empty() ? 1 : 0;
437             }
438              
439             sub _is_one {
440             # return true if arg is one
441 3062     3062   18442 my $x = $_[1];
442              
443 3062 100       7253 return 0 if $x->Size() != $bits; # if size mismatch
444 2720         7035 $x->equal($one);
445             }
446              
447             sub _is_two {
448             # return true if arg is two
449 58     58   1866 my $x = $_[1];
450              
451 58 100       188 return 0 if $x->Size() != $bits; # if size mismatch
452 50         147 $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   1226 $_[1]->bit_test(0) ? 0 : 1;
467             }
468              
469             sub _is_odd {
470             # return true if arg is odd
471              
472 196 100   196   3165 $_[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   601236 my $x = $_[1];
481 1830 50       4356 return "Undefined" unless defined $x;
482 1830 100       3811 return "$x is not a reference to Bit::Vector" if ref($x) ne 'Bit::Vector';
483              
484 1829 50       5350 return "$x is negative" if $x->Sign() < 0;
485              
486             # Get the size.
487              
488 1829         3797 my $xs = $x -> Size();
489              
490             # The size must be a multiple of the chunk size.
491              
492 1829         3803 my $ns = $chunk * int($xs / $chunk);
493 1829 50       3458 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         3447 my $imax = $x -> Max(); # index of highest non-zero bit
500 1829 100       3212 my $nmin = $imax < 0 ? 1 : $imax + 2; # minimum number of bits required
501 1829         3400 $ns = $chunk * __ceil($nmin / $chunk); # minimum size in whole chunks
502 1829 50       3227 if ($xs != $ns) {
503 0         0 return "Size($x) is $xs bits, but only $ns bits are needed.";
504             }
505              
506 1829         3315 0;
507             }
508              
509             sub _mod {
510 766     766   4805 my ($class, $x, $y) = @_;
511              
512             # Get current sizes.
513              
514 766         1215 my $xs = $x -> Size();
515 766         1138 my $ys = $y -> Size();
516              
517             # Resize to a common size.
518              
519 766         1070 my $ns = __max($xs, $ys);
520 766 50       1315 $x -> Resize($ns) if $xs < $ns;
521 766 100       1474 $y -> Resize($ns) if $ys < $ns;
522 766         1640 my $quo = Bit::Vector -> new($ns);
523 766         1261 my $rem = Bit::Vector -> new($ns);
524              
525             # Get the quotient.
526              
527 766         15567 $quo -> Divide($x, $y, $rem);
528              
529             # Resize $y back to its original size, if necessary.
530              
531 766 100       1466 $y -> Resize($ys) if $ys < $ns;
532              
533 766         1169 $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 207330     207330   281366 my ($class, $x) = @_;
567              
568 207330         302147 my $bits_allocated = $x->Size();
569 207330 100       320155 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 172577         256299 my $imax = $x->Max();
576 172577 100       248688 my $bits_needed = $imax < 0 ? 1 : 2 + $imax;
577 172577         240977 $bits_needed = $chunk * __ceil($bits_needed / $chunk);
578              
579 172577 100       269887 if ($bits_allocated > $bits_needed) {
580 139190         212460 $x->Resize($bits_needed);
581             }
582              
583 172577         251272 $x;
584             }
585              
586             ###############################################################################
587             # helper/utility functions
588              
589             # maximum of 2 values
590              
591             sub __max {
592 49120     49120   64801 my ($m, $n) = @_;
593 49120 100       82561 $m > $n ? $m : $n;
594             }
595              
596             # ceiling function
597              
598             sub __ceil {
599 410935     410935   469392 my $x = shift;
600 410935         487259 my $ix = int $x;
601 410935 100       645147 ($ix >= $x) ? $ix : $ix + 1;
602             }
603              
604             1;
605              
606             __END__