/
60-bigint.t
108 lines (89 loc) · 4.92 KB
/
60-bigint.t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#! nqp
use nqpmo;
plan(36);
my $knowhow := pir::get_knowhow__P();
my $bi_type := $knowhow.new_type(:name('TestBigInt'), :repr('P6bigint'));
$bi_type.HOW.compose($bi_type);
sub str($x) { nqp::tostr_I($x) };
sub iseq($x, $y) { nqp::iseq_I($x, nqp::box_i($y, $bi_type)) }
sub box($x) { nqp::box_i($x, $bi_type) }
my $one := box(1);
my $b := nqp::fromstr_I('-123', $one);
my $c := box(-123);
ok(str($b) eq '-123', 'can round-trip negative number (string)');
ok(str($c) eq '-123', 'can round-trip negative number (string) by boxing');
ok(nqp::unbox_i($b) == -123, 'can round-trip negative number by unboxing');
ok(!nqp::iseq_I($one, $b), 'nqp::iseq_I can return false');
ok(nqp::iseq_I($one, $one), 'nqp::iseq_I can return true');
ok(iseq(nqp::mul_I($b, $b, $b), 15129,), 'multiplication');
ok(iseq(nqp::add_I($b, $b, $b), -246,), 'addition');
ok(nqp::iseq_I(nqp::sub_I($b, $b, $b), nqp::box_i(0, $bi_type)), 'subtraction');
ok(nqp::iseq_I(nqp::div_I($b, $b, $b), $one), 'division');
ok(iseq(nqp::bitshiftl_I($one, 3, $one), 8), 'bitshift left');
ok(iseq($one, 1), 'original not modified by bitshift left');
ok(iseq(nqp::bitshiftr_I(box(16), 4, $one), 1), 'bitshift right');
ok(iseq(nqp::bitand_I(box(0xdead), box(0xbeef), $one), 0x9ead), 'bit and');
ok(iseq(nqp::bitor_I( box(0xdead), box(0xbeef), $one), 0xfeef), 'bit or');
ok(iseq(nqp::bitxor_I(box(0xdead), box(0xbeef), $one), 0x6042), 'bit xor');
ok(iseq(nqp::bitneg_I(box(-123), $one), 122), 'bit negation');
ok(iseq(nqp::bitand_I(nqp::fromstr_I('-1073741825', $one), $one, $one), 1),
'Bit ops (RT 109740)');
# Now we'll create a type that boxes a P6bigint.
my $bi_boxer := $knowhow.new_type(:name('TestPerl6Int'), :repr('P6opaque'));
$bi_boxer.HOW.add_attribute($bi_boxer, NQPAttribute.new(
:name('$!value'), :type($bi_type), :box_target(1)
));
$bi_boxer.HOW.compose($bi_boxer);
# Try some basic operations with it.
my $box_val_1 := nqp::box_i(4, $bi_boxer);
ok(iseq($box_val_1, 4), 'can box to a complex type with a P6bigint target');
my $box_val_2 := nqp::fromstr_I('38', $bi_boxer);
ok(iseq($box_val_2, 38), 'can get a bigint from a string with boxing type');
ok(iseq(nqp::add_I($box_val_1, $box_val_2, $bi_boxer), 42), 'addition works on boxing type');
# Note that the last argument to pow_I should be capable of boxing a num,
# so $bi_type is wrong here. But so far we only test the integer case,
# so we can get away with it.
my $big := nqp::pow_I($c, box(42), $bi_type, $bi_type);
ok(str($big) eq '5970554685064519004265641008828923248442340700473500698131071806779372733915289638628729', 'pow (int, positive)');
ok(iseq(nqp::pow_I(box(0), $big, $bi_type, $bi_type), 0), 'pow 0 ** large_number');
ok(iseq(nqp::pow_I($one, $big, $bi_type, $bi_type), 1), 'pow 1 ** large_number');
# test conversion to float
# try it with 2 ** 100, because that's big enough not to fit into a single
# int, but can be represented exactly in a double
$big := nqp::pow_I(box(2), box(100), $bi_type, $bi_type);
ok(nqp::iseq_n(nqp::tonum_I($big), nqp::pow_n(2, 100)), '2**100 to float');
$big := nqp::pow_I(box(-2), box(101), $bi_type, $bi_type);
ok(nqp::iseq_n(nqp::tonum_I($big), nqp::pow_n(-2, 101)), '(-2)**101 to float');
# the mantissa can hold much information accurately, so test that too
my $factor := 123456789;
$big := nqp::mul_I($big, box($factor), $bi_type);
ok(nqp::iseq_n(nqp::tonum_I($big), nqp::mul_n($factor, nqp::pow_n(-2, 101))), "$factor * (-2)**101 to float");
$big := 1e16;
my $converted := nqp::tonum_I(nqp::fromstr_I('10000000000000000', $bi_type));
ok(nqp::abs_n($big - $converted) / $big < 1e-4, 'bigint -> float, 1e16');
my $float := 123456789e240;
ok(nqp::iseq_n($float, nqp::tonum_I(nqp::fromnum_I($float, $bi_type))),
'to_num and from_num round-trip');
my $small_float := 1e3;
ok(nqp::iseq_n($small_float, nqp::tonum_I(nqp::fromnum_I($small_float, $bi_type))),
'to_num and from_num round-trip on small floats');
my $medium_float := 1e14;
ok(nqp::iseq_n($medium_float, nqp::tonum_I(nqp::fromnum_I($medium_float, $bi_type))),
'to_num and from_num round-trip on medium sized floats');
$float := -$float;
ok(nqp::iseq_n($float, nqp::tonum_I(nqp::fromnum_I($float, $bi_type))),
'to_num and from_num round-trip (negative number)');
ok(nqp::base_I(box(-1234), 10) eq '-1234', 'base_I with base 10');
ok(nqp::base_I(box(-1234), 16) eq '-4D2', 'base_I with base 16');
ok(str(nqp::expmod_I(
nqp::fromstr_I('2988348162058574136915891421498819466320163312926952423791023078876139', $bi_type),
nqp::fromstr_I('2351399303373464486466122544523690094744975233415544072992656881240319', $bi_type),
nqp::fromstr_I('10000000000000000000000000000000000000000', $bi_type),
$bi_type,
)) eq '1527229998585248450016808958343740453059', 'nqp::expmod_I');
ok(nqp::div_In(box(1234500), box(100)) == 12345, 'div_In santiy');
my $n := nqp::div_In(
nqp::pow_I(box(203), box(200), $bi_type, $bi_type),
nqp::pow_I(box(200), box(200), $bi_type, $bi_type),
);
ok(nqp::abs_n($n - 19.6430286394751) < 1e-10, 'div_In with big numbers');