1# -*- mode: perl; -*-
2
3# Binary, octal, and hexadecimal floating point literals were introduced in
4# v5.22.0.
5#
6# - It wasn't until v5.28.0 that binary, octal, and hexadecimal floating point
7#   literals were converted to the correct value on perls compiled with quadmath
8#   support.
9#
10# - It wasn't until v5.34.0 that binary and octal floating point literals worked
11#   correctly with constant overloading. Before v5.34.0, it seems like the
12#   second character is always silently converted to an "x", so, e.g., "0b1.1p8"
13#   is passed to the overload::constant subroutine as "0x1.1p8", and "01.1p+8"
14#   is passed as "0x.1p+8".
15#
16# - Octal floating point literals using the "0o" prefix were introduced in
17#   v5.34.0.
18
19# Note that all numeric literals that should not be overloaded must be quoted.
20
21use strict;
22use warnings;
23
24use Test::More tests => "118";
25
26use bigint;
27
28my $class = "Math::BigInt";
29my $x;
30
31################################################################################
32# The following tests should be identical for Math::BigInt, Math::BigFloat and
33# Math::BigRat.
34
35# These are handled by "binary".
36
37$x= 0xff;
38is($x, "255", "hexadecimal integer literal 0xff");
39is(ref($x), $class, "value is a $class");
40
41SKIP: {
42    # Hexadecimal literals using the "0X" prefix require v5.14.0.
43    skip "perl v5.14.0 required for hexadecimal integer literals"
44      . " with '0X' prefix", "2" if $] < "5.014";
45
46    $x = eval "0XFF";
47    is($x, "255", "hexadecimal integer literal 0XFF");
48    is(ref($x), $class, "value is a $class");
49}
50
51$x = 0377;
52is($x, "255", "octal integer literal 0377");
53is(ref($x), $class, "value is a $class");
54
55SKIP: {
56    # Octal literals using the "0o" prefix were introduced in v5.34.0.
57    skip "perl v5.34.0 required for octal floating point literals"
58      . " with '0o' prefix", "4" if $] < "5.034";
59
60    for my $str (qw/ 0o377 0O377 /) {
61        $x = eval $str;
62        is($x, "255", "octal integer literal $str");
63        is(ref($x), $class, "value is a $class");
64    }
65}
66
67$x = 0b11111111;
68is($x, "255", "binary integer literal 0b11111111");
69is(ref($x), $class, "value is a $class");
70
71SKIP: {
72    # Binary literals using the "0B" prefix require v5.14.0.
73    skip "perl v5.14.0 required for binary integer literals"
74      . " with '0B' prefix", "2" if $] < "5.014";
75
76    $x = eval "0B11111111";
77    is($x, "255", "binary integer literal 0B11111111");
78    is(ref($x), $class, "value is a $class");
79}
80
81# These are handled by "float".
82
83$x = 999999999999999999999999999999999999999999999999999999999999999999999999;
84is($x,
85   "999999999999999999999999999999999999999999999999999999999999999999999999",
86   "decimal integer literal " . ("9" x 72));
87is(ref($x), $class, "value is a $class");
88
89$x = 1e72 - 1;
90is($x,
91   "999999999999999999999999999999999999999999999999999999999999999999999999",
92   "literal 1e72 - 1");
93is(ref($x), $class, "value is a $class");
94
95# These are handled by "float".
96
97SKIP: {
98    # Hexadecimal floating point literals require v5.28.0.
99    skip "perl v5.28.0 required for hexadecimal floating point literals",
100      "6" * "2" + "2" * "2" if $] < "5.028";
101
102    for my $str (qw/ 0x1.3ap+8 0X1.3AP+8
103                     0x1.3ap8  0X1.3AP8
104                     0x13a0p-4 0X13A0P-4 /)
105    {
106        $x = eval $str;
107        is($x, "314", "hexadecimal floating point literal $str");
108        is(ref($x), $class, "value is a $class");
109    }
110
111    for my $str (qw/ 0x0.0p+8 0X0.0P+8 /)
112    {
113        $x = eval $str;
114        is($x, "0", "hexadecimal floating point literal $str");
115        is(ref($x), $class, "value is a $class");
116    }
117}
118
119SKIP: {
120    # Octal floating point literals using the "0o" prefix require v5.34.0.
121    skip "perl v5.34.0 required for octal floating point literals"
122      . " with '0o' prefix", "6" * "2" + "6" * "2" if $] < "5.034";
123
124    for my $str (qw/ 0o1.164p+8 0O1.164P+8
125                     0o1.164p8  0O1.164P8
126                     0o11640p-4 0O11640P-4 /)
127    {
128        $x = eval $str;
129        is($x, "314", "octal floating point literal $str");
130        is(ref($x), $class, "value is a $class");
131    }
132
133    for my $str (qw/ 0o0.0p+8 0O0.0P+8
134                     0o0.0p8  0O0.0P8
135                     0o0.0p-8 0O0.0P-8 /)
136    {
137        $x = eval $str;
138        is($x, "0", "octal floating point literal $str");
139        is(ref($x), $class, "value is a $class");
140    }
141}
142
143SKIP: {
144    # Octal floating point literals using the "0" prefix require v5.32.0.
145    skip "perl v5.32.0 required for octal floating point literals",
146      "6" * "2" + "6" * "2" if $] < "5.032";
147
148    for my $str (qw/ 01.164p+8 01.164P+8
149                     01.164p8  01.164P8
150                     011640p-4 011640P-4 /)
151    {
152        $x = eval $str;
153        is($x, "314", "octal floating point literal $str");
154        is(ref($x), $class, "value is a $class");
155    }
156
157    for my $str (qw/ 00.0p+8 00.0P+8
158                     00.0p8 00.0P8
159                     00.0p-8 00.0P-8 /)
160    {
161        $x = eval $str;
162        is($x, "0", "octal floating point literal $str");
163        is(ref($x), $class, "value is a $class");
164    }
165}
166
167SKIP: {
168    # Binary floating point literals require v5.32.0.
169    skip "perl v5.32.0 required for binary floating point literals",
170      "6" * "2" + "6" * "2" if $] < "5.032";
171
172    for my $str (qw/ 0b1.0011101p+8   0B1.0011101P+8
173                     0b1.0011101p8    0B1.0011101P8
174                     0b10011101000p-2 0B10011101000P-2 /)
175    {
176        $x = eval $str;
177        is($x, "314", "binary floating point literal $str");
178        is(ref($x), $class, "value is a $class");
179    }
180
181    for my $str (qw/ 0b0p+8 0B0P+8
182                     0b0p8 0B0P8
183                     0b0p-8 0B0P-8
184                   /)
185    {
186        $x = eval $str;
187        is($x, "0", "binary floating point literal $str");
188        is(ref($x), $class, "value is a $class");
189    }
190}
191
192# These are handled by "integer".
193
194$x = 314;
195is($x, "314", "integer literal 314");
196like(ref($x), qr/^Math::BigInt(::Lite)?$/,
197     "value is a Math::BigInt or Math::BigInt::Lite");
198
199$x = 0;
200is($x, "0", "integer literal 0");
201like(ref($x), qr/^Math::BigInt(::Lite)?$/,
202     "value is a Math::BigInt or Math::BigInt::Lite");
203
204$x = 2 ** 255;
205is($x,
206   "578960446186580977117854925043439539266"
207   . "34992332820282019728792003956564819968",
208   "2 ** 255");
209is(ref($x), $class, "value is a $class");
210
211# These are handled by "binary".
212
213{
214    no warnings "portable";     # protect against "non-portable" warnings
215
216    # hexadecimal constant
217    $x = 0x123456789012345678901234567890;
218    is($x,
219       "94522879687365475552814062743484560",
220       "hexadecimal constant 0x123456789012345678901234567890");
221    is(ref($x), $class, "value is a $class");
222
223    # octal constant
224    $x = 012345676543210123456765432101234567654321;
225    is($x,
226       "1736132869400711976876385488263403729",
227       "octal constant 012345676543210123456765432101234567654321");
228    is(ref($x), $class, "value is a $class");
229
230    # binary constant
231    $x = 0b01010100011001010110110001110011010010010110000101101101;
232    is($x,
233       "23755414508757357",
234       "binary constant 0b0101010001100101011011000111"
235       . "0011010010010110000101101101");
236    is(ref($x), $class, "value is a $class");
237}
238