1#!./perl
2
3BEGIN {
4    chdir 't' if -d 't';
5    require './test.pl';
6    set_up_inc('../lib');
7    eval { my $q = pack "q", 0 };
8    skip_all('no 64-bit types') if $@;
9}
10
11# This could use many more tests.
12
13# so that using > 0xfffffff constants and
14# 32+ bit integers don't cause noise
15use warnings;
16no warnings qw(overflow portable);
17use Config;
18
19# as 6 * 6 = 36, the last digit of 6**n will always be six. Hence the last
20# digit of 16**n will always be six. Hence 16**n - 1 will always end in 5.
21# Assumption is that UVs will always be a multiple of 4 bits long.
22
23my $UV_max = ~0;
24die "UV_max eq '$UV_max', doesn't end in 5; your UV isn't 4n bits long :-(."
25  unless $UV_max =~ /5$/;
26my $UV_max_less3 = $UV_max - 3;
27my $maths_preserves_UVs = $UV_max_less3 =~ /^\d+2$/;   # 5 - 3 is 2.
28if ($maths_preserves_UVs) {
29  print "# This perl's maths preserves all bits of a UV.\n";
30} else {
31  print "# This perl's maths does not preserve all bits of a UV.\n";
32}
33
34my $q = 12345678901;
35my $r = 23456789012;
36my $f = 0xffffffff;
37my $x;
38my $y;
39
40$x = unpack "q", pack "q", $q;
41cmp_ok($x, '==', $q);
42cmp_ok($x, '>', $f);
43
44
45$x = sprintf("%lld", 12345678901);
46is($x, $q);
47cmp_ok($x, '>', $f);
48
49$x = sprintf("%lld", $q);
50cmp_ok($x, '==', $q);
51is($x, $q);
52cmp_ok($x, '>', $f);
53
54$x = sprintf("%Ld", $q);
55cmp_ok($x, '==', $q);
56is($x, $q);
57cmp_ok($x, '>', $f);
58
59$x = sprintf("%qd", $q);
60cmp_ok($x, '==', $q);
61is($x, $q);
62cmp_ok($x, '>', $f);
63
64
65$x = sprintf("%llx", $q);
66cmp_ok(hex $x, '==', 0x2dfdc1c35);
67cmp_ok(hex $x, '>', $f);
68
69$x = sprintf("%Lx", $q);
70cmp_ok(hex $x, '==', 0x2dfdc1c35);
71cmp_ok(hex $x, '>', $f);
72
73$x = sprintf("%qx", $q);
74cmp_ok(hex $x, '==', 0x2dfdc1c35);
75cmp_ok(hex $x, '>', $f);
76
77$x = sprintf("%llo", $q);
78cmp_ok(oct "0$x", '==', 0133767016065);
79cmp_ok(oct $x, '>', $f);
80
81$x = sprintf("%Lo", $q);
82cmp_ok(oct "0$x", '==', 0133767016065);
83cmp_ok(oct $x, '>', $f);
84
85$x = sprintf("%qo", $q);
86cmp_ok(oct "0$x", '==', 0133767016065);
87cmp_ok(oct $x, '>', $f);
88
89$x = sprintf("%llb", $q);
90cmp_ok(oct "0b$x", '==', 0b1011011111110111000001110000110101);
91cmp_ok(oct "0b$x", '>', $f);
92
93$x = sprintf("%Lb", $q);
94cmp_ok(oct "0b$x", '==', 0b1011011111110111000001110000110101);
95cmp_ok(oct "0b$x", '>', $f);
96
97$x = sprintf("%qb", $q);
98cmp_ok(oct "0b$x", '==', 0b1011011111110111000001110000110101);
99cmp_ok(oct "0b$x", '>', $f);
100
101
102$x = sprintf("%llu", $q);
103is($x, $q);
104cmp_ok($x, '>', $f);
105
106$x = sprintf("%Lu", $q);
107cmp_ok($x, '==', $q);
108is($x, $q);
109cmp_ok($x, '>', $f);
110
111$x = sprintf("%qu", $q);
112cmp_ok($x, '==', $q);
113is($x, $q);
114cmp_ok($x, '>', $f);
115
116
117$x = sprintf("%D", $q);
118cmp_ok($x, '==', $q);
119is($x, $q);
120cmp_ok($x, '>', $f);
121
122$x = sprintf("%U", $q);
123cmp_ok($x, '==', $q);
124is($x, $q);
125cmp_ok($x, '>', $f);
126
127$x = sprintf("%O", $q);
128cmp_ok(oct $x, '==', $q);
129cmp_ok(oct $x, '>', $f);
130
131
132$x = $q + $r;
133cmp_ok($x, '==', 35802467913);
134cmp_ok($x, '>', $f);
135
136$x = $q - $r;
137cmp_ok($x, '==', -11111110111);
138cmp_ok(-$x, '>', $f);
139
140SKIP: {
141    # Unicos has imprecise doubles (14 decimal digits or so),
142    # especially if operating near the UV/IV limits the low-order bits
143    # become mangled even by simple arithmetic operations.
144    skip('too imprecise numbers on unicos') if $^O eq 'unicos';
145
146    $x = $q * 1234567;
147    cmp_ok($x, '==', 15241567763770867);
148    cmp_ok($x, '>', $f);
149
150    $x /= 1234567;
151    cmp_ok($x, '==', $q);
152    cmp_ok($x, '>', $f);
153
154    $x = 98765432109 % 12345678901;
155    cmp_ok($x, '==', 901);
156
157    # The following 12 tests adapted from op/inc.
158
159    $a = 9223372036854775807;
160    $c = $a++;
161    cmp_ok($a, '==', 9223372036854775808);
162
163    $a = 9223372036854775807;
164    $c = ++$a;
165    cmp_ok($a, '==', 9223372036854775808);
166    cmp_ok($c, '==', $a);
167
168    $a = 9223372036854775807;
169    $c = $a + 1;
170    cmp_ok($a, '==', 9223372036854775807);
171    cmp_ok($c, '==', 9223372036854775808);
172
173    $a = -9223372036854775808;
174    {
175	no warnings 'imprecision';
176	$c = $a--;
177    }
178    cmp_ok($a, '==', -9223372036854775809);
179    cmp_ok($c, '==', -9223372036854775808);
180
181    $a = -9223372036854775808;
182    {
183	no warnings 'imprecision';
184	$c = --$a;
185    }
186    cmp_ok($a, '==', -9223372036854775809);
187    cmp_ok($c, '==', $a);
188
189    $a = -9223372036854775808;
190    $c = $a - 1;
191    cmp_ok($a, '==', -9223372036854775808);
192    cmp_ok($c, '==', -9223372036854775809);
193
194    $a = 9223372036854775808;
195    $a = -$a;
196    {
197	no warnings 'imprecision';
198	$c = $a--;
199    }
200    cmp_ok($a, '==', -9223372036854775809);
201    cmp_ok($c, '==', -9223372036854775808);
202
203    $a = 9223372036854775808;
204    $a = -$a;
205    {
206	no warnings 'imprecision';
207	$c = --$a;
208    }
209    cmp_ok($a, '==', -9223372036854775809);
210    cmp_ok($c, '==', $a);
211
212    $a = 9223372036854775808;
213    $a = -$a;
214    $c = $a - 1;
215    cmp_ok($a, '==', -9223372036854775808);
216    cmp_ok($c, '==', -9223372036854775809);
217
218    $a = 9223372036854775808;
219    $b = -$a;
220    {
221	no warnings 'imprecision';
222	$c = $b--;
223    }
224    cmp_ok($b, '==', -$a-1);
225    cmp_ok($c, '==', -$a);
226
227    $a = 9223372036854775808;
228    $b = -$a;
229    {
230	no warnings 'imprecision';
231	$c = --$b;
232    }
233    cmp_ok($b, '==', -$a-1);
234    cmp_ok($c, '==', $b);
235
236    $a = 9223372036854775808;
237    $b = -$a;
238    $b = $b - 1;
239    cmp_ok($b, '==', -(++$a));
240}
241
242
243$x = '';
244cmp_ok((vec($x, 1, 64) = $q), '==', $q);
245
246cmp_ok(vec($x, 1, 64), '==', $q);
247cmp_ok(vec($x, 1, 64), '>', $f);
248
249cmp_ok(vec($x, 0, 64), '==', 0);
250cmp_ok(vec($x, 2, 64), '==', 0);
251
252cmp_ok(~0, '==', 0xffffffffffffffff);
253
254cmp_ok((0xffffffff<<32), '==', 0xffffffff00000000);
255
256cmp_ok(((0xffffffff)<<32)>>32, '==', 0xffffffff);
257
258cmp_ok(1<<63, '==', 0x8000000000000000);
259
260is((sprintf "%#Vx", 1<<63), '0x8000000000000000');
261
262cmp_ok((0x8000000000000000 | 1), '==', 0x8000000000000001);
263
264cmp_ok((0xf000000000000000 & 0x8000000000000000), '==', 0x8000000000000000);
265cmp_ok((0xf000000000000000 ^ 0xfffffffffffffff0), '==', 0x0ffffffffffffff0);
266
267
268is((sprintf "%b", ~0),
269   '1111111111111111111111111111111111111111111111111111111111111111');
270
271
272is((sprintf "%64b", ~0),
273   '1111111111111111111111111111111111111111111111111111111111111111');
274
275is((sprintf "%d", ~0>>1),'9223372036854775807');
276is((sprintf "%u", ~0),'18446744073709551615');
277
278# If the 53..55 fail you have problems in the parser's string->int conversion,
279# see toke.c:scan_num().
280
281$q = -9223372036854775808;
282is("$q","-9223372036854775808");
283
284$q =  9223372036854775807;
285is("$q","9223372036854775807");
286
287$q = 18446744073709551615;
288is("$q","18446744073709551615");
289
290# Test that sv_2nv then sv_2iv is the same as sv_2iv direct
291# fails if whatever Atol is defined as can't actually cope with >32 bits.
292my $num = 4294967297;
293my $string = "4294967297";
294{
295  use integer;
296  $num += 0;
297  $string += 0;
298}
299is($num, $string);
300
301# Test that sv_2nv then sv_2uv is the same as sv_2uv direct
302$num = 4294967297;
303$string = "4294967297";
304$num &= 0;
305$string &= 0;
306is($num, $string);
307
308$q = "18446744073709551616e0";
309$q += 0;
310isnt($q, "18446744073709551615");
311
312# 0xFFFFFFFFFFFFFFFF ==  1 * 3 * 5 * 17 * 257 * 641 * 65537 * 6700417'
313$q = 0xFFFFFFFFFFFFFFFF / 3;
314cmp_ok($q, '==', 0x5555555555555555);
315SKIP: {
316    skip("Maths does not preserve UVs", 2) unless $maths_preserves_UVs;
317    cmp_ok($q, '!=', 0x5555555555555556);
318    skip("All UV division is precise as NVs, so is done as NVs", 1)
319	if $Config{d_nv_preserves_uv};
320    unlike($q, qr/[e.]/);
321}
322
323$q = 0xFFFFFFFFFFFFFFFF % 0x5555555555555555;
324cmp_ok($q, '==', 0);
325
326$q = 0xFFFFFFFFFFFFFFFF % 0xFFFFFFFFFFFFFFF0;
327cmp_ok($q, '==', 0xF);
328
329$q = 0x8000000000000000 % 9223372036854775807;
330cmp_ok($q, '==', 1);
331
332$q = 0x8000000000000000 % -9223372036854775807;
333cmp_ok($q, '==', -9223372036854775806);
334
335{
336    use integer;
337    $q = hex "0x123456789abcdef0";
338    cmp_ok($q, '==', 0x123456789abcdef0);
339    cmp_ok($q, '!=', 0x123456789abcdef1);
340    unlike($q, qr/[e.]/, 'Should not be floating point');
341
342    $q = oct "0x123456789abcdef0";
343    cmp_ok($q, '==', 0x123456789abcdef0);
344    cmp_ok($q, '!=', 0x123456789abcdef1);
345    unlike($q, qr/[e.]/, 'Should not be floating point');
346
347    $q = oct "765432176543217654321";
348    cmp_ok($q, '==', 0765432176543217654321);
349    cmp_ok($q, '!=', 0765432176543217654322);
350    unlike($q, qr/[e.]/, 'Should not be floating point');
351
352    $q = oct "0b0101010101010101010101010101010101010101010101010101010101010101";
353    cmp_ok($q, '==', 0x5555555555555555);
354    cmp_ok($q, '!=', 0x5555555555555556);
355    unlike($q, qr/[e.]/, 'Should not be floating point');
356}
357
358# trigger various attempts to negate IV_MIN
359
360cmp_ok  0x8000000000000000 / -0x8000000000000000, '==', -1, '(IV_MAX+1) / IV_MIN';
361cmp_ok -0x8000000000000000 /  0x8000000000000000, '==', -1, 'IV_MIN / (IV_MAX+1)';
362cmp_ok  0x8000000000000000 / -1, '==', -0x8000000000000000, '(IV_MAX+1) / -1';
363cmp_ok                   0 % -0x8000000000000000, '==',  0, '0 % IV_MIN';
364cmp_ok -0x8000000000000000 % -0x8000000000000000, '==',  0, 'IV_MIN % IV_MIN';
365
366# check addition/subtraction with values 1 bit below max ranges
367{
368    my $a_3ff = 0x3fffffffffffffff;
369    my $a_400 = 0x4000000000000000;
370    my $a_7fe = 0x7ffffffffffffffe;
371    my $a_7ff = 0x7fffffffffffffff;
372    my $a_800 = 0x8000000000000000;
373
374    my $m_3ff = -$a_3ff;
375    my $m_400 = -$a_400;
376    my $m_7fe = -$a_7fe;
377    my $m_7ff = -$a_7ff;
378
379    cmp_ok $a_3ff, '==',  4611686018427387903, "1bit  a_3ff";
380    cmp_ok $m_3ff, '==', -4611686018427387903, "1bit -a_3ff";
381    cmp_ok $a_400, '==',  4611686018427387904, "1bit  a_400";
382    cmp_ok $m_400, '==', -4611686018427387904, "1bit -a_400";
383    cmp_ok $a_7fe, '==',  9223372036854775806, "1bit  a_7fe";
384    cmp_ok $m_7fe, '==', -9223372036854775806, "1bit -a_7fe";
385    cmp_ok $a_7ff, '==',  9223372036854775807, "1bit  a_7ff";
386    cmp_ok $m_7ff, '==', -9223372036854775807, "1bit -a_7ff";
387    cmp_ok $a_800, '==',  9223372036854775808, "1bit  a_800";
388
389    cmp_ok $a_3ff + $a_3ff, '==',  $a_7fe, "1bit  a_3ff +  a_3ff";
390    cmp_ok $m_3ff + $a_3ff, '==',       0, "1bit -a_3ff +  a_3ff";
391    cmp_ok $a_3ff + $m_3ff, '==',       0, "1bit  a_3ff + -a_3ff";
392    cmp_ok $m_3ff + $m_3ff, '==',  $m_7fe, "1bit -a_3ff + -a_3ff";
393
394    cmp_ok $a_3ff - $a_3ff, '==',       0, "1bit  a_3ff -  a_3ff";
395    cmp_ok $m_3ff - $a_3ff, '==',  $m_7fe, "1bit -a_3ff -  a_3ff";
396    cmp_ok $a_3ff - $m_3ff, '==',  $a_7fe, "1bit  a_3ff - -a_3ff";
397    cmp_ok $m_3ff - $m_3ff, '==',       0, "1bit -a_3ff - -a_3ff";
398
399    cmp_ok $a_3ff + $a_400, '==',  $a_7ff, "1bit  a_3ff +  a_400";
400    cmp_ok $m_3ff + $a_400, '==',       1, "1bit -a_3ff +  a_400";
401    cmp_ok $a_3ff + $m_400, '==',      -1, "1bit  a_3ff + -a_400";
402    cmp_ok $m_3ff + $m_400, '==',  $m_7ff, "1bit -a_3ff + -a_400";
403
404    cmp_ok $a_3ff - $a_400, '==',      -1, "1bit  a_3ff -  a_400";
405    cmp_ok $m_3ff - $a_400, '==',  $m_7ff, "1bit -a_3ff -  a_400";
406    cmp_ok $a_3ff - $m_400, '==',  $a_7ff, "1bit  a_3ff - -a_400";
407    cmp_ok $m_3ff - $m_400, '==',       1, "1bit -a_3ff - -a_400";
408
409    cmp_ok $a_400 + $a_3ff, '==',  $a_7ff, "1bit  a_400 +  a_3ff";
410    cmp_ok $m_400 + $a_3ff, '==',      -1, "1bit -a_400 +  a_3ff";
411    cmp_ok $a_400 + $m_3ff, '==',       1, "1bit  a_400 + -a_3ff";
412    cmp_ok $m_400 + $m_3ff, '==',  $m_7ff, "1bit -a_400 + -a_3ff";
413
414    cmp_ok $a_400 - $a_3ff, '==',       1, "1bit  a_400 -  a_3ff";
415    cmp_ok $m_400 - $a_3ff, '==',  $m_7ff, "1bit -a_400 -  a_3ff";
416    cmp_ok $a_400 - $m_3ff, '==',  $a_7ff, "1bit  a_400 - -a_3ff";
417    cmp_ok $m_400 - $m_3ff, '==',      -1, "1bit -a_400 - -a_3ff";
418}
419
420# check multiplication with values using approx half the total bits
421{
422    my $a  =         0xffffffff;
423    my $aa = 0xfffffffe00000001;
424    my $m  = -$a;
425    my $mm = -$aa;
426
427    cmp_ok $a,      '==',            4294967295, "halfbits   a";
428    cmp_ok $m,      '==',           -4294967295, "halfbits  -a";
429    cmp_ok $aa,     '==',  18446744065119617025, "halfbits  aa";
430    cmp_ok $mm,     '==', -18446744065119617025, "halfbits -aa";
431    cmp_ok $a * $a, '==',                   $aa, "halfbits  a *  a";
432    cmp_ok $m * $a, '==',                   $mm, "halfbits -a *  a";
433    cmp_ok $a * $m, '==',                   $mm, "halfbits  a * -a";
434    cmp_ok $m * $m, '==',                   $aa, "halfbits -a * -a";
435}
436
437# check multiplication where the 2 args multiply to 2^62 .. 2^65
438
439{
440    my $exp62 = (2**62);
441    my $exp63 = (2**63);
442    my $exp64 = (2**64);
443    my $exp65 = (2**65);
444    cmp_ok $exp62, '==',  4611686018427387904, "2**62";
445    cmp_ok $exp63, '==',  9223372036854775808, "2**63";
446    cmp_ok $exp64, '==', 18446744073709551616, "2**64";
447    cmp_ok $exp65, '==', 36893488147419103232, "2**65";
448
449    my @exp = ($exp62, $exp63, $exp64, $exp65);
450    for my $i (0..63) {
451        for my $x (0..3) {
452            my $j = 62 - $i + $x;
453            next if $j < 0 or $j > 63;
454
455            my $a = (1 << $i);
456            my $b = (1 << $j);
457            my $c = $a * $b;
458            cmp_ok $c, '==', $exp[$x], "(1<<$i) * (1<<$j)";
459        }
460    }
461}
462
463done_testing();
464