1# -*- mode: perl; -*-
2
3# Test Math::BigInt::Calc
4
5use strict;
6use warnings;
7
8use Test::More tests => 524;
9
10use Math::BigInt::Calc;
11
12my ($BASE_LEN, $BASE, $AND_BITS, $XOR_BITS, $OR_BITS,
13    $BASE_LEN_SMALL, $MAX_VAL,
14    $MAX_BITS, $MAX_EXP_F, $MAX_EXP_I, $USE_INT)
15  = Math::BigInt::Calc -> _base_len();
16
17note(<<"EOF");
18
19BASE_LEN  = $BASE_LEN
20BASE      = $BASE
21MAX_VAL   = $MAX_VAL
22AND_BITS  = $AND_BITS
23XOR_BITS  = $XOR_BITS
24OR_BITS   = $OR_BITS
25MAX_EXP_F = $MAX_EXP_F
26MAX_EXP_I = $MAX_EXP_I
27USE_INT   = $USE_INT
28EOF
29
30my $LIB = 'Math::BigInt::Calc';
31my $REF = 'Math::BigInt::Calc';
32
33# _new and _str
34
35my $x = $LIB->_new("123");
36my $y = $LIB->_new("321");
37is(ref($x), $REF, q|ref($x) is a $REF|);
38is($LIB->_str($x), 123,     qq|$LIB->_str(\$x) = 123|);
39is($LIB->_str($y), 321,     qq|$LIB->_str(\$y) = 321|);
40
41###############################################################################
42# _add, _sub, _mul, _div
43
44is($LIB->_str($LIB->_add($x, $y)), 444,
45   qq|$LIB->_str($LIB->_add(\$x, \$y)) = 444|);
46is($LIB->_str($LIB->_sub($x, $y)), 123,
47   qq|$LIB->_str($LIB->_sub(\$x, \$y)) = 123|);
48is($LIB->_str($LIB->_mul($x, $y)), 39483,
49   qq|$LIB->_str($LIB->_mul(\$x, \$y)) = 39483|);
50is($LIB->_str($LIB->_div($x, $y)), 123,
51   qq|$LIB->_str($LIB->_div(\$x, \$y)) = 123|);
52
53###############################################################################
54# check that mul/div doesn't change $y
55# and returns the same reference, not something new
56
57is($LIB->_str($LIB->_mul($x, $y)), 39483,
58   qq|$LIB->_str($LIB->_mul(\$x, \$y)) = 39483|);
59is($LIB->_str($x), 39483,
60   qq|$LIB->_str(\$x) = 39483|);
61is($LIB->_str($y), 321,
62   qq|$LIB->_str(\$y) = 321|);
63
64is($LIB->_str($LIB->_div($x, $y)), 123,
65   qq|$LIB->_str($LIB->_div(\$x, \$y)) = 123|);
66is($LIB->_str($x), 123,
67   qq|$LIB->_str(\$x) = 123|);
68is($LIB->_str($y), 321,
69   qq|$LIB->_str(\$y) = 321|);
70
71$x = $LIB->_new("39483");
72my ($x1, $r1) = $LIB->_div($x, $y);
73is("$x1", "$x", q|"$x1" = "$x"|);
74$LIB->_inc($x1);
75is("$x1", "$x", q|"$x1" = "$x"|);
76is($LIB->_str($r1), "0", qq|$LIB->_str(\$r1) = "0"|);
77
78$x = $LIB->_new("39483");       # reset
79
80###############################################################################
81
82my $z = $LIB->_new("2");
83is($LIB->_str($LIB->_add($x, $z)), 39485,
84   qq|$LIB->_str($LIB->_add(\$x, \$z)) = 39485|);
85my ($re, $rr) = $LIB->_div($x, $y);
86
87is($LIB->_str($re), 123, qq|$LIB->_str(\$re) = 123|);
88is($LIB->_str($rr), 2,   qq|$LIB->_str(\$rr) = 2|);
89
90# is_zero, _is_one, _one, _zero
91
92ok(! $LIB->_is_zero($x), qq|$LIB->_is_zero(\$x)|);
93ok(! $LIB->_is_one($x),  qq|$LIB->_is_one(\$x)|);
94
95is($LIB->_str($LIB->_zero()), "0", qq|$LIB->_str($LIB->_zero()) = "0"|);
96is($LIB->_str($LIB->_one()),  "1", qq|$LIB->_str($LIB->_one())  = "1"|);
97
98# _two() and _ten()
99
100is($LIB->_str($LIB->_two()), "2",  qq|$LIB->_str($LIB->_two()) = "2"|);
101is($LIB->_str($LIB->_ten()), "10", qq|$LIB->_str($LIB->_ten()) = "10"|);
102
103ok(! $LIB->_is_ten($LIB->_two()), qq|$LIB->_is_ten($LIB->_two()) is false|);
104ok(  $LIB->_is_two($LIB->_two()), qq|$LIB->_is_two($LIB->_two()) is true|);
105ok(  $LIB->_is_ten($LIB->_ten()), qq|$LIB->_is_ten($LIB->_ten()) is true|);
106ok(! $LIB->_is_two($LIB->_ten()), qq|$LIB->_is_two($LIB->_ten()) is false|);
107
108ok(  $LIB->_is_one($LIB->_one()), qq|$LIB->_is_one($LIB->_one()) is true|);
109ok(! $LIB->_is_one($LIB->_two()), qq|$LIB->_is_one($LIB->_two()) is false|);
110ok(! $LIB->_is_one($LIB->_ten()), qq|$LIB->_is_one($LIB->_ten()) is false|);
111
112ok(! $LIB->_is_one($LIB->_zero()),  qq/$LIB->_is_one($LIB->_zero()) is false/);
113ok(  $LIB->_is_zero($LIB->_zero()), qq|$LIB->_is_zero($LIB->_zero()) is true|);
114ok(! $LIB->_is_zero($LIB->_one()),  qq/$LIB->_is_zero($LIB->_one()) is false/);
115
116# is_odd, is_even
117
118ok(  $LIB->_is_odd($LIB->_one()),   qq/$LIB->_is_odd($LIB->_one()) is true/);
119ok(! $LIB->_is_odd($LIB->_zero()),  qq/$LIB->_is_odd($LIB->_zero()) is false/);
120ok(! $LIB->_is_even($LIB->_one()),  qq/$LIB->_is_even($LIB->_one()) is false/);
121ok(  $LIB->_is_even($LIB->_zero()), qq/$LIB->_is_even($LIB->_zero()) is true/);
122
123# _alen and _len
124
125for my $method (qw/_alen _len/) {
126    $x = $LIB->_new("1");
127    is($LIB->$method($x), 1, qq|$LIB->$method(\$x) = 1|);
128    $x = $LIB->_new("12");
129    is($LIB->$method($x), 2, qq|$LIB->$method(\$x) = 2|);
130    $x = $LIB->_new("123");
131    is($LIB->$method($x), 3, qq|$LIB->$method(\$x) = 3|);
132    $x = $LIB->_new("1234");
133    is($LIB->$method($x), 4, qq|$LIB->$method(\$x) = 4|);
134    $x = $LIB->_new("12345");
135    is($LIB->$method($x), 5, qq|$LIB->$method(\$x) = 5|);
136    $x = $LIB->_new("123456");
137    is($LIB->$method($x), 6, qq|$LIB->$method(\$x) = 6|);
138    $x = $LIB->_new("1234567");
139    is($LIB->$method($x), 7, qq|$LIB->$method(\$x) = 7|);
140    $x = $LIB->_new("12345678");
141    is($LIB->$method($x), 8, qq|$LIB->$method(\$x) = 8|);
142    $x = $LIB->_new("123456789");
143    is($LIB->$method($x), 9, qq|$LIB->$method(\$x) = 9|);
144
145    $x = $LIB->_new("8");
146    is($LIB->$method($x), 1, qq|$LIB->$method(\$x) = 1|);
147    $x = $LIB->_new("21");
148    is($LIB->$method($x), 2, qq|$LIB->$method(\$x) = 2|);
149    $x = $LIB->_new("321");
150    is($LIB->$method($x), 3, qq|$LIB->$method(\$x) = 3|);
151    $x = $LIB->_new("4321");
152    is($LIB->$method($x), 4, qq|$LIB->$method(\$x) = 4|);
153    $x = $LIB->_new("54321");
154    is($LIB->$method($x), 5, qq|$LIB->$method(\$x) = 5|);
155    $x = $LIB->_new("654321");
156    is($LIB->$method($x), 6, qq|$LIB->$method(\$x) = 6|);
157    $x = $LIB->_new("7654321");
158    is($LIB->$method($x), 7, qq|$LIB->$method(\$x) = 7|);
159    $x = $LIB->_new("87654321");
160    is($LIB->$method($x), 8, qq|$LIB->$method(\$x) = 8|);
161    $x = $LIB->_new("987654321");
162    is($LIB->$method($x), 9, qq|$LIB->$method(\$x) = 9|);
163
164    $x = $LIB->_new("0");
165    is($LIB->$method($x), 1, qq|$LIB->$method(\$x) = 1|);
166    $x = $LIB->_new("20");
167    is($LIB->$method($x), 2, qq|$LIB->$method(\$x) = 2|);
168    $x = $LIB->_new("320");
169    is($LIB->$method($x), 3, qq|$LIB->$method(\$x) = 3|);
170    $x = $LIB->_new("4320");
171    is($LIB->$method($x), 4, qq|$LIB->$method(\$x) = 4|);
172    $x = $LIB->_new("54320");
173    is($LIB->$method($x), 5, qq|$LIB->$method(\$x) = 5|);
174    $x = $LIB->_new("654320");
175    is($LIB->$method($x), 6, qq|$LIB->$method(\$x) = 6|);
176    $x = $LIB->_new("7654320");
177    is($LIB->$method($x), 7, qq|$LIB->$method(\$x) = 7|);
178    $x = $LIB->_new("87654320");
179    is($LIB->$method($x), 8, qq|$LIB->$method(\$x) = 8|);
180    $x = $LIB->_new("987654320");
181    is($LIB->$method($x), 9, qq|$LIB->$method(\$x) = 9|);
182
183    for (my $i = 1; $i < 9; $i++) {
184        my $a = "$i" . '0' x ($i - 1);
185        $x = $LIB->_new($a);
186        is($LIB->_len($x), $i, qq|$LIB->_len(\$x) = $i|);
187    }
188}
189
190# _digit
191
192$x = $LIB->_new("123456789");
193is($LIB->_digit($x, 0),   9, qq|$LIB->_digit(\$x, 0) = 9|);
194is($LIB->_digit($x, 1),   8, qq|$LIB->_digit(\$x, 1) = 8|);
195is($LIB->_digit($x, 2),   7, qq|$LIB->_digit(\$x, 2) = 7|);
196is($LIB->_digit($x, 8),   1, qq|$LIB->_digit(\$x, 8) = 1|);
197is($LIB->_digit($x, 9),   0, qq|$LIB->_digit(\$x, 9) = 0|);
198is($LIB->_digit($x, -1),  1, qq|$LIB->_digit(\$x, -1) = 1|);
199is($LIB->_digit($x, -2),  2, qq|$LIB->_digit(\$x, -2) = 2|);
200is($LIB->_digit($x, -3),  3, qq|$LIB->_digit(\$x, -3) = 3|);
201is($LIB->_digit($x, -9),  9, qq|$LIB->_digit(\$x, -9) = 9|);
202is($LIB->_digit($x, -10), 0, qq|$LIB->_digit(\$x, -10) = 0|);
203
204# _copy
205
206foreach (qw/ 1 12 123 1234 12345 123456 1234567 12345678 123456789/) {
207    $x = $LIB->_new("$_");
208    is($LIB->_str($LIB->_copy($x)), "$_",
209       qq|$LIB->_str($LIB->_copy(\$x)) = "$_"|);
210    is($LIB->_str($x), "$_",           # did _copy destroy original x?
211       qq|$LIB->_str(\$x) = "$_"|);
212}
213
214# _zeros
215
216$x = $LIB->_new("1256000000");
217is($LIB->_zeros($x), 6, qq|$LIB->_zeros(\$x) = 6|);
218
219$x = $LIB->_new("152");
220is($LIB->_zeros($x), 0, qq|$LIB->_zeros(\$x) = 0|);
221
222$x = $LIB->_new("123000");
223is($LIB->_zeros($x), 3, qq|$LIB->_zeros(\$x) = 3|);
224
225$x = $LIB->_new("0");
226is($LIB->_zeros($x), 0, qq|$LIB->_zeros(\$x) = 0|);
227
228# _lsft, _rsft
229
230$x = $LIB->_new("10");
231$y = $LIB->_new("3");
232is($LIB->_str($LIB->_lsft($x, $y, 10)), 10000,
233   qq|$LIB->_str($LIB->_lsft(\$x, \$y, 10)) = 10000|);
234
235$x = $LIB->_new("20");
236$y = $LIB->_new("3");
237is($LIB->_str($LIB->_lsft($x, $y, 10)), 20000,
238   qq|$LIB->_str($LIB->_lsft(\$x, \$y, 10)) = 20000|);
239
240$x = $LIB->_new("128");
241$y = $LIB->_new("4");
242is($LIB->_str($LIB->_lsft($x, $y, 2)), 128 << 4,
243   qq|$LIB->_str($LIB->_lsft(\$x, \$y, 2)) = 128 << 4|);
244
245$x = $LIB->_new("1000");
246$y = $LIB->_new("3");
247is($LIB->_str($LIB->_rsft($x, $y, 10)), 1,
248   qq|$LIB->_str($LIB->_rsft(\$x, \$y, 10)) = 1|);
249
250$x = $LIB->_new("20000");
251$y = $LIB->_new("3");
252is($LIB->_str($LIB->_rsft($x, $y, 10)), 20,
253   qq|$LIB->_str($LIB->_rsft(\$x, \$y, 10)) = 20|);
254
255$x = $LIB->_new("256");
256$y = $LIB->_new("4");
257is($LIB->_str($LIB->_rsft($x, $y, 2)), 256 >> 4,
258   qq|$LIB->_str($LIB->_rsft(\$x, \$y, 2)) = 256 >> 4|);
259
260$x = $LIB->_new("6411906467305339182857313397200584952398");
261$y = $LIB->_new("45");
262is($LIB->_str($LIB->_rsft($x, $y, 10)), 0,
263   qq|$LIB->_str($LIB->_rsft(\$x, \$y, 10)) = 0|);
264
265# _lsft() with large bases
266
267for my $xstr ("1", "2", "3") {
268    for my $nstr ("1", "2", "3") {
269        for my $bpow (25, 50, 75) {
270            my $bstr = "1" . ("0" x $bpow);
271            my $expected = $xstr . ("0" x ($bpow * $nstr));
272            my $xobj = $LIB->_new($xstr);
273            my $nobj = $LIB->_new($nstr);
274            my $bobj = $LIB->_new($bstr);
275
276            is($LIB->_str($LIB->_lsft($xobj, $nobj, $bobj)), $expected,
277               qq|$LIB->_str($LIB->_lsft($LIB->_new("$xstr"), |
278                                    . qq|$LIB->_new("$nstr"), |
279                                    . qq|$LIB->_new("$bstr")))|);
280            is($LIB->_str($nobj), $nstr, q|$n is unmodified|);
281            is($LIB->_str($bobj), $bstr, q|$b is unmodified|);
282        }
283    }
284}
285
286# _acmp
287
288$x = $LIB->_new("123456789");
289$y = $LIB->_new("987654321");
290is($LIB->_acmp($x, $y), -1, qq|$LIB->_acmp(\$x, \$y) = -1|);
291is($LIB->_acmp($y, $x), 1,  qq|$LIB->_acmp(\$y, \$x) = 1|);
292is($LIB->_acmp($x, $x), 0,  qq|$LIB->_acmp(\$x, \$x) = 0|);
293is($LIB->_acmp($y, $y), 0,  qq|$LIB->_acmp(\$y, \$y) = 0|);
294$x = $LIB->_new("12");
295$y = $LIB->_new("12");
296is($LIB->_acmp($x, $y), 0,  qq|$LIB->_acmp(\$x, \$y) = 0|);
297$x = $LIB->_new("21");
298is($LIB->_acmp($x, $y), 1,  qq|$LIB->_acmp(\$x, \$y) = 1|);
299is($LIB->_acmp($y, $x), -1, qq|$LIB->_acmp(\$y, \$x) = -1|);
300$x = $LIB->_new("123456789");
301$y = $LIB->_new("1987654321");
302is($LIB->_acmp($x, $y), -1, qq|$LIB->_acmp(\$x, \$y) = -1|);
303is($LIB->_acmp($y, $x), +1, qq|$LIB->_acmp(\$y, \$x) = +1|);
304
305$x = $LIB->_new("1234567890123456789");
306$y = $LIB->_new("987654321012345678");
307is($LIB->_acmp($x, $y), 1,  qq|$LIB->_acmp(\$x, \$y) = 1|);
308is($LIB->_acmp($y, $x), -1, qq|$LIB->_acmp(\$y, \$x) = -1|);
309is($LIB->_acmp($x, $x), 0,  qq|$LIB->_acmp(\$x, \$x) = 0|);
310is($LIB->_acmp($y, $y), 0,  qq|$LIB->_acmp(\$y, \$y) = 0|);
311
312$x = $LIB->_new("1234");
313$y = $LIB->_new("987654321012345678");
314is($LIB->_acmp($x, $y), -1, qq|$LIB->_acmp(\$x, \$y) = -1|);
315is($LIB->_acmp($y, $x), 1,  qq|$LIB->_acmp(\$y, \$x) = 1|);
316is($LIB->_acmp($x, $x), 0,  qq|$LIB->_acmp(\$x, \$x) = 0|);
317is($LIB->_acmp($y, $y), 0,  qq|$LIB->_acmp(\$y, \$y) = 0|);
318
319# _modinv
320
321$x = $LIB->_new("8");
322$y = $LIB->_new("5033");
323my ($xmod, $sign) = $LIB->_modinv($x, $y);
324is($LIB->_str($xmod), "629",            # -629 % 5033 == 4404
325   qq|$LIB->_str(\$xmod) = "629"|);
326is($sign, "-", q|$sign = "-"|);
327
328# _div
329
330$x = $LIB->_new("3333");
331$y = $LIB->_new("1111");
332is($LIB->_str(scalar($LIB->_div($x, $y))), 3,
333   qq|$LIB->_str(scalar($LIB->_div(\$x, \$y))) = 3|);
334
335$x = $LIB->_new("33333");
336$y = $LIB->_new("1111");
337($x, $y) = $LIB->_div($x, $y);
338is($LIB->_str($x), 30, qq|$LIB->_str(\$x) = 30|);
339is($LIB->_str($y),  3, qq|$LIB->_str(\$y) = 3|);
340
341$x = $LIB->_new("123");
342$y = $LIB->_new("1111");
343($x, $y) = $LIB->_div($x, $y);
344is($LIB->_str($x), 0,   qq|$LIB->_str(\$x) = 0|);
345is($LIB->_str($y), 123, qq|$LIB->_str(\$y) = 123|);
346
347# _num
348
349foreach (qw/1 12 123 1234 12345 1234567 12345678 123456789 1234567890/) {
350
351    $x = $LIB->_new("$_");
352    is(ref($x), $REF, q|ref($x) = "$REF"|);
353    is($LIB->_str($x), "$_", qq|$LIB->_str(\$x) = "$_"|);
354
355    $x = $LIB->_num($x);
356    is(ref($x), "", q|ref($x) = ""|);
357    is($x,      $_, qq|\$x = $_|);
358}
359
360# _sqrt
361
362$x = $LIB->_new("144");
363is($LIB->_str($LIB->_sqrt($x)), "12",
364   qq|$LIB->_str($LIB->_sqrt(\$x)) = "12"|);
365$x = $LIB->_new("144000000000000");
366is($LIB->_str($LIB->_sqrt($x)), "12000000",
367   qq|$LIB->_str($LIB->_sqrt(\$x)) = "12000000"|);
368
369# _root
370
371$x = $LIB->_new("81");
372my $n = $LIB->_new("3");        # 4*4*4 = 64, 5*5*5 = 125
373is($LIB->_str($LIB->_root($x, $n)), "4",
374   qq|$LIB->_str($LIB->_root(\$x, \$n)) = "4"|); # 4.xx => 4.0
375
376$x = $LIB->_new("81");
377$n = $LIB->_new("4");          # 3*3*3*3 == 81
378is($LIB->_str($LIB->_root($x, $n)), "3",
379   qq|$LIB->_str($LIB->_root(\$x, \$n)) = "3"|);
380
381# _pow (and _root)
382
383$x = $LIB->_new("0");
384$n = $LIB->_new("3");          # 0 ** y => 0
385is($LIB->_str($LIB->_pow($x, $n)), 0,
386   qq|$LIB->_str($LIB->_pow(\$x, \$n)) = 0|);
387
388$x = $LIB->_new("3");
389$n = $LIB->_new("0");          # x ** 0 => 1
390is($LIB->_str($LIB->_pow($x, $n)), 1,
391   qq|$LIB->_str($LIB->_pow(\$x, \$n)) = 1|);
392
393$x = $LIB->_new("1");
394$n = $LIB->_new("3");          # 1 ** y => 1
395is($LIB->_str($LIB->_pow($x, $n)), 1,
396   qq|$LIB->_str($LIB->_pow(\$x, \$n)) = 1|);
397
398$x = $LIB->_new("5");
399$n = $LIB->_new("1");          # x ** 1 => x
400is($LIB->_str($LIB->_pow($x, $n)), 5,
401   qq|$LIB->_str($LIB->_pow(\$x, \$n)) = 5|);
402
403$x = $LIB->_new("81");
404$n = $LIB->_new("3");          # 81 ** 3 == 531441
405is($LIB->_str($LIB->_pow($x, $n)), 81 ** 3,
406   qq|$LIB->_str($LIB->_pow(\$x, \$n)) = 81 ** 3|);
407
408is($LIB->_str($LIB->_root($x, $n)), 81,
409   qq|$LIB->_str($LIB->_root(\$x, \$n)) = 81|);
410
411$x = $LIB->_new("81");
412is($LIB->_str($LIB->_pow($x, $n)), 81 ** 3,
413   qq|$LIB->_str($LIB->_pow(\$x, \$n)) = 81 ** 3|);
414is($LIB->_str($LIB->_pow($x, $n)), "150094635296999121",      # 531441 ** 3
415   qq|$LIB->_str($LIB->_pow(\$x, \$n)) = "150094635296999121"|);
416
417is($LIB->_str($LIB->_root($x, $n)), "531441",
418   qq|$LIB->_str($LIB->_root(\$x, \$n)) = "531441"|);
419is($LIB->_str($LIB->_root($x, $n)), "81",
420   qq|$LIB->_str($LIB->_root(\$x, \$n)) = "81"|);
421
422$x = $LIB->_new("81");
423$n = $LIB->_new("14");
424is($LIB->_str($LIB->_pow($x, $n)), "523347633027360537213511521",
425   qq|$LIB->_str($LIB->_pow(\$x, \$n)) = "523347633027360537213511521"|);
426is($LIB->_str($LIB->_root($x, $n)), "81",
427   qq|$LIB->_str($LIB->_root(\$x, \$n)) = "81"|);
428
429$x = $LIB->_new("523347633027360537213511520");
430is($LIB->_str($LIB->_root($x, $n)), "80",
431   qq|$LIB->_str($LIB->_root(\$x, \$n)) = "80"|);
432
433$x = $LIB->_new("523347633027360537213511522");
434is($LIB->_str($LIB->_root($x, $n)), "81",
435   qq|$LIB->_str($LIB->_root(\$x, \$n)) = "81"|);
436
437my $res = [ qw/9 31 99 316 999 3162 9999 31622 99999/ ];
438
439# 99 ** 2 = 9801, 999 ** 2 = 998001 etc
440
441for my $i (2 .. 9) {
442    $x = '9' x $i;
443    $x = $LIB->_new($x);
444    $n = $LIB->_new("2");
445    my $rc = '9' x ($i-1). '8' . '0' x ($i - 1) . '1';
446    print "# _pow( ", '9' x $i, ", 2) \n" unless
447      is($LIB->_str($LIB->_pow($x, $n)), $rc,
448         qq|$LIB->_str($LIB->_pow(\$x, \$n)) = $rc|);
449
450  SKIP: {
451        # If $i > $BASE_LEN, the test takes a really long time.
452        skip "$i > $BASE_LEN", 2 unless $i <= $BASE_LEN;
453
454        $x = '9' x $i;
455        $x = $LIB->_new($x);
456        $n = '9' x $i;
457        $n = $LIB->_new($n);
458        print "# _root( ", '9' x $i, ", ", 9 x $i, ") \n";
459        print "# _root( ", '9' x $i, ", ", 9 x $i, ") \n"
460          unless is($LIB->_str($LIB->_root($x, $n)), '1',
461                    qq|$LIB->_str($LIB->_root(\$x, \$n)) = '1'|);
462
463        $x = '9' x $i;
464        $x = $LIB->_new($x);
465        $n = $LIB->_new("2");
466        print "# BASE_LEN $BASE_LEN _root( ", '9' x $i, ", ", 9 x $i, ") \n"
467          unless is($LIB->_str($LIB->_root($x, $n)), $res->[$i-2],
468                    qq|$LIB->_str($LIB->_root(\$x, \$n)) = $res->[$i-2]|);
469    }
470}
471
472##############################################################################
473# _fac
474
475$x = $LIB->_new("0");
476is($LIB->_str($LIB->_fac($x)), "1",
477   qq|$LIB->_str($LIB->_fac(\$x)) = "1"|);
478
479$x = $LIB->_new("1");
480is($LIB->_str($LIB->_fac($x)), "1",
481   qq|$LIB->_str($LIB->_fac(\$x)) = "1"|);
482
483$x = $LIB->_new("2");
484is($LIB->_str($LIB->_fac($x)), "2",
485   qq|$LIB->_str($LIB->_fac(\$x)) = "2"|);
486
487$x = $LIB->_new("3");
488is($LIB->_str($LIB->_fac($x)), "6",
489   qq|$LIB->_str($LIB->_fac(\$x)) = "6"|);
490
491$x = $LIB->_new("4");
492is($LIB->_str($LIB->_fac($x)), "24",
493   qq|$LIB->_str($LIB->_fac(\$x)) = "24"|);
494
495$x = $LIB->_new("5");
496is($LIB->_str($LIB->_fac($x)), "120",
497   qq|$LIB->_str($LIB->_fac(\$x)) = "120"|);
498
499$x = $LIB->_new("10");
500is($LIB->_str($LIB->_fac($x)), "3628800",
501   qq|$LIB->_str($LIB->_fac(\$x)) = "3628800"|);
502
503$x = $LIB->_new("11");
504is($LIB->_str($LIB->_fac($x)), "39916800",
505   qq|$LIB->_str($LIB->_fac(\$x)) = "39916800"|);
506
507$x = $LIB->_new("12");
508is($LIB->_str($LIB->_fac($x)), "479001600",
509   qq|$LIB->_str($LIB->_fac(\$x)) = "479001600"|);
510
511$x = $LIB->_new("13");
512is($LIB->_str($LIB->_fac($x)), "6227020800",
513   qq|$LIB->_str($LIB->_fac(\$x)) = "6227020800"|);
514
515# test that _fac modifies $x in place for small arguments
516
517$x = $LIB->_new("3");
518$LIB->_fac($x);
519is($LIB->_str($x), "6",
520   qq|$LIB->_str(\$x) = "6"|);
521
522$x = $LIB->_new("13");
523$LIB->_fac($x);
524is($LIB->_str($x), "6227020800",
525   qq|$LIB->_str(\$x) = "6227020800"|);
526
527# _inc and _dec
528
529for (qw/1 11 121 1231 12341 1234561 12345671 123456781 1234567891/) {
530    $x = $LIB->_new("$_");
531    $LIB->_inc($x);
532    my $expected = substr($_, 0, length($_) - 1) . '2';
533    is($LIB->_str($x), $expected, qq|$LIB->_str(\$x) = $expected|);
534    $LIB->_dec($x);
535    is($LIB->_str($x), $_, qq|$LIB->_str(\$x) = $_|);
536}
537
538for (qw/19 119 1219 12319 1234519 12345619 123456719 1234567819/) {
539    $x = $LIB->_new("$_");
540    $LIB->_inc($x);
541    my $expected = substr($_, 0, length($_)-2) . '20';
542    is($LIB->_str($x), $expected, qq|$LIB->_str(\$x) = $expected|);
543    $LIB->_dec($x);
544    is($LIB->_str($x), $_, qq|$LIB->_str(\$x) = $_|);
545}
546
547for (1 .. 20) {
548    my $p = "9" x $_;                       # = $q - 1
549    my $q = "1" . ("0" x $_);               # = $p + 1
550
551    $x = $LIB->_new("$p");
552    $LIB->_inc($x);
553    is($LIB->_str($x), $q, qq|\$x = $LIB->_new("$p"); $LIB->_inc()|);
554
555    $x = $LIB->_new("$q");
556    $LIB->_dec($x);
557    is($LIB->_str($x), $p, qq|\$x = $LIB->_new("$q"); $LIB->_dec()|);
558}
559
560for (1 .. 20) {
561    my $p = "1" . ("0" x $_);               # = $q - 1
562    my $q = "1" . ("0" x ($_ - 1)) . "1";   # = $p + 1
563
564    $x = $LIB->_new("$p");
565    $LIB->_inc($x);
566    is($LIB->_str($x), $q, qq|\$x = $LIB->_new("$p"); $LIB->_inc()|);
567
568    $x = $LIB->_new("$q");
569    $LIB->_dec($x);
570    is($LIB->_str($x), $p, qq|\$x = $LIB->_new("$q"); $LIB->_dec()|);
571}
572
573$x = $LIB->_new("1000");
574$LIB->_inc($x);
575is($LIB->_str($x), "1001", qq|$LIB->_str(\$x) = "1001"|);
576$LIB->_dec($x);
577is($LIB->_str($x), "1000", qq|$LIB->_str(\$x) = "1000"|);
578
579my $BL = $LIB -> _base_len();
580
581$x = '1' . '0' x $BL;
582$z = '1' . '0' x ($BL - 1);
583$z .= '1';
584$x = $LIB->_new($x);
585$LIB->_inc($x);
586is($LIB->_str($x), $z, qq|$LIB->_str(\$x) = $z|);
587
588$x = '1' . '0' x $BL;
589$z = '9' x $BL;
590$x = $LIB->_new($x);
591$LIB->_dec($x);
592is($LIB->_str($x), $z, qq|$LIB->_str(\$x) = $z|);
593
594# should not happen:
595# $x = $LIB->_new("-2");
596# $y = $LIB->_new("4");
597# is($LIB->_acmp($x, $y), -1, qq|$LIB->_acmp($x, $y) = -1|);
598
599###############################################################################
600# _mod
601
602$x = $LIB->_new("1000");
603$y = $LIB->_new("3");
604is($LIB->_str(scalar($LIB->_mod($x, $y))), 1,
605   qq|$LIB->_str(scalar($LIB->_mod(\$x, \$y))) = 1|);
606
607$x = $LIB->_new("1000");
608$y = $LIB->_new("2");
609is($LIB->_str(scalar($LIB->_mod($x, $y))), 0,
610   qq|$LIB->_str(scalar($LIB->_mod(\$x, \$y))) = 0|);
611
612# _and, _or, _xor
613
614$x = $LIB->_new("5");
615$y = $LIB->_new("2");
616is($LIB->_str(scalar($LIB->_xor($x, $y))), 7,
617   qq|$LIB->_str(scalar($LIB->_xor(\$x, \$y))) = 7|);
618
619$x = $LIB->_new("5");
620$y = $LIB->_new("2");
621is($LIB->_str(scalar($LIB->_or($x, $y))), 7,
622   qq|$LIB->_str(scalar($LIB->_or(\$x, \$y))) = 7|);
623
624$x = $LIB->_new("5");
625$y = $LIB->_new("3");
626is($LIB->_str(scalar($LIB->_and($x, $y))), 1,
627   qq|$LIB->_str(scalar($LIB->_and(\$x, \$y))) = 1|);
628
629# _from_hex, _from_bin, _from_oct
630
631is($LIB->_str($LIB->_from_hex("0xFf")), 255,
632   qq|$LIB->_str($LIB->_from_hex("0xFf")) = 255|);
633is($LIB->_str($LIB->_from_bin("0b10101011")), 160+11,
634   qq|$LIB->_str($LIB->_from_bin("0b10101011")) = 160+11|);
635is($LIB->_str($LIB->_from_oct("0100")), 8*8,
636   qq|$LIB->_str($LIB->_from_oct("0100")) = 8*8|);
637is($LIB->_str($LIB->_from_oct("01000")), 8*8*8,
638   qq|$LIB->_str($LIB->_from_oct("01000")) = 8*8*8|);
639is($LIB->_str($LIB->_from_oct("010001")), 8*8*8*8+1,
640   qq|$LIB->_str($LIB->_from_oct("010001")) = 8*8*8*8+1|);
641is($LIB->_str($LIB->_from_oct("010007")), 8*8*8*8+7,
642   qq|$LIB->_str($LIB->_from_oct("010007")) = 8*8*8*8+7|);
643
644# _as_hex, _as_bin, as_oct
645
646is($LIB->_str($LIB->_from_hex($LIB->_as_hex($LIB->_new("128")))), 128,
647   qq|$LIB->_str($LIB->_from_hex($LIB->_as_hex(|
648   . qq|$LIB->_new("128")))) = 128|);
649is($LIB->_str($LIB->_from_bin($LIB->_as_bin($LIB->_new("128")))), 128,
650   qq|$LIB->_str($LIB->_from_bin($LIB->_as_bin(|
651   . qq|$LIB->_new("128")))) = 128|);
652is($LIB->_str($LIB->_from_oct($LIB->_as_oct($LIB->_new("128")))), 128,
653   qq|$LIB->_str($LIB->_from_oct($LIB->_as_oct(|
654   . qq|$LIB->_new("128")))) = 128|);
655
656is($LIB->_str($LIB->_from_oct($LIB->_as_oct($LIB->_new("123456")))),
657   123456,
658   qq|$LIB->_str($LIB->_from_oct($LIB->_as_oct|
659   . qq|($LIB->_new("123456")))) = 123456|);
660is($LIB->_str($LIB->_from_oct($LIB->_as_oct($LIB->_new("123456789")))),
661   "123456789",
662   qq|$LIB->_str($LIB->_from_oct($LIB->_as_oct(|
663   . qq|$LIB->_new("123456789")))) = "123456789"|);
664is($LIB->_str($LIB->_from_oct($LIB->_as_oct($LIB->_new("1234567890123")))),
665   "1234567890123",
666   qq|$LIB->_str($LIB->_from_oct($LIB->_as_oct(|
667   . qq|$LIB->_new("1234567890123")))) = "1234567890123"|);
668
669my $long = "123456789012345678901234567890";
670is($LIB->_str($LIB->_from_hex($LIB->_as_hex($LIB->_new($long)))), $long,
671   qq|$LIB->_str($LIB->_from_hex($LIB->_as_hex(|
672   . qq|$LIB->_new("$long")))) = "$long"|);
673is($LIB->_str($LIB->_from_bin($LIB->_as_bin($LIB->_new($long)))), $long,
674   qq|$LIB->_str($LIB->_from_bin($LIB->_as_bin(|
675   . qq|$LIB->_new("$long")))) = "$long"|);
676is($LIB->_str($LIB->_from_oct($LIB->_as_oct($LIB->_new($long)))), $long,
677   qq|$LIB->_str($LIB->_from_oct($LIB->_as_oct(|
678   . qq|$LIB->_new("$long")))) = "$long"|);
679
680is($LIB->_str($LIB->_from_hex($LIB->_as_hex($LIB->_new("0")))), 0,
681   qq|$LIB->_str($LIB->_from_hex($LIB->_as_hex(|
682   . qq|$LIB->_new("0")))) = 0|);
683is($LIB->_str($LIB->_from_bin($LIB->_as_bin($LIB->_new("0")))), 0,
684   qq|$LIB->_str($LIB->_from_bin($LIB->_as_bin(|
685   . qq|$LIB->_new("0")))) = 0|);
686is($LIB->_str($LIB->_from_oct($LIB->_as_oct($LIB->_new("0")))), 0,
687   qq|$LIB->_str($LIB->_from_oct($LIB->_as_oct(|
688   . qq|$LIB->_new("0")))) = 0|);
689
690is($LIB->_as_hex($LIB->_new("0")), "0x0",
691   qq|$LIB->_as_hex($LIB->_new("0")) = "0x0"|);
692is($LIB->_as_bin($LIB->_new("0")), "0b0",
693   qq|$LIB->_as_bin($LIB->_new("0")) = "0b0"|);
694is($LIB->_as_oct($LIB->_new("0")), "00",
695   qq|$LIB->_as_oct($LIB->_new("0")) = "00"|);
696
697is($LIB->_as_hex($LIB->_new("12")), "0xc",
698   qq|$LIB->_as_hex($LIB->_new("12")) = "0xc"|);
699is($LIB->_as_bin($LIB->_new("12")), "0b1100",
700   qq|$LIB->_as_bin($LIB->_new("12")) = "0b1100"|);
701is($LIB->_as_oct($LIB->_new("64")), "0100",
702   qq|$LIB->_as_oct($LIB->_new("64")) = "0100"|);
703
704# _1ex
705
706is($LIB->_str($LIB->_1ex(0)), "1",
707   qq|$LIB->_str($LIB->_1ex(0)) = "1"|);
708is($LIB->_str($LIB->_1ex(1)), "10",
709   qq|$LIB->_str($LIB->_1ex(1)) = "10"|);
710is($LIB->_str($LIB->_1ex(2)), "100",
711   qq|$LIB->_str($LIB->_1ex(2)) = "100"|);
712is($LIB->_str($LIB->_1ex(12)), "1000000000000",
713   qq|$LIB->_str($LIB->_1ex(12)) = "1000000000000"|);
714is($LIB->_str($LIB->_1ex(16)), "10000000000000000",
715   qq|$LIB->_str($LIB->_1ex(16)) = "10000000000000000"|);
716
717# _check
718
719$x = $LIB->_new("123456789");
720is($LIB->_check($x), 0,
721   qq|$LIB->_check(\$x) = 0|);
722is($LIB->_check(123), "123 is not a reference",
723   qq|$LIB->_check(123) = "123 is not a reference"|);
724
725###############################################################################
726# __strip_zeros
727
728{
729    no strict 'refs';
730
731    # correct empty arrays
732    $x = &{$LIB."::__strip_zeros"}([]);
733    is(@$x, 1, q|@$x = 1|);
734    is($x->[0], 0, q|$x->[0] = 0|);
735
736    # don't strip single elements
737    $x = &{$LIB."::__strip_zeros"}([0]);
738    is(@$x, 1, q|@$x = 1|);
739    is($x->[0], 0, q|$x->[0] = 0|);
740    $x = &{$LIB."::__strip_zeros"}([1]);
741    is(@$x, 1, q|@$x = 1|);
742    is($x->[0], 1, q|$x->[0] = 1|);
743
744    # don't strip non-zero elements
745    $x = &{$LIB."::__strip_zeros"}([0, 1]);
746    is(@$x, 2, q|@$x = 2|);
747    is($x->[0], 0, q|$x->[0] = 0|);
748    is($x->[1], 1, q|$x->[1] = 1|);
749    $x = &{$LIB."::__strip_zeros"}([0, 1, 2]);
750    is(@$x, 3, q|@$x = 3|);
751    is($x->[0], 0, q|$x->[0] = 0|);
752    is($x->[1], 1, q|$x->[1] = 1|);
753    is($x->[2], 2, q|$x->[2] = 2|);
754
755    # but strip leading zeros
756    $x = &{$LIB."::__strip_zeros"}([0, 1, 2, 0]);
757    is(@$x, 3, q|@$x = 3|);
758    is($x->[0], 0, q|$x->[0] = 0|);
759    is($x->[1], 1, q|$x->[1] = 1|);
760    is($x->[2], 2, q|$x->[2] = 2|);
761
762    $x = &{$LIB."::__strip_zeros"}([0, 1, 2, 0, 0]);
763    is(@$x, 3, q|@$x = 3|);
764    is($x->[0], 0, q|$x->[0] = 0|);
765    is($x->[1], 1, q|$x->[1] = 1|);
766    is($x->[2], 2, q|$x->[2] = 2|);
767
768    $x = &{$LIB."::__strip_zeros"}([0, 1, 2, 0, 0, 0]);
769    is(@$x, 3, q|@$x = 3|);
770    is($x->[0], 0, q|$x->[0] = 0|);
771    is($x->[1], 1, q|$x->[1] = 1|);
772    is($x->[2], 2, q|$x->[2] = 2|);
773
774    # collapse multiple zeros
775    $x = &{$LIB."::__strip_zeros"}([0, 0, 0, 0]);
776    is(@$x, 1, q|@$x = 1|);
777    is($x->[0], 0, q|$x->[0] = 0|);
778}
779