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.32.0 that binary and octal floating point literals worked 11# correctly with constant overloading. Before v5.32.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 => "171"; 25 26use Math::BigRat ":constant"; 27 28my $class = "Math::BigRat"; 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 requires 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"); 196is(ref($x), $class, "value is a $class"); 197 198$x = 0; 199is($x, "0", "integer literal 0"); 200is(ref($x), $class, "value is a $class"); 201 202$x = 2 ** 255; 203is($x, 204 "578960446186580977117854925043439539266" 205 . "34992332820282019728792003956564819968", 206 "2 ** 255"); 207is(ref($x), $class, "value is a $class"); 208 209# These are handled by "binary". 210 211{ 212 no warnings "portable"; # protect against "non-portable" warnings 213 214 # hexadecimal constant 215 $x = 0x123456789012345678901234567890; 216 is($x, 217 "94522879687365475552814062743484560", 218 "hexadecimal constant 0x123456789012345678901234567890"); 219 is(ref($x), $class, "value is a $class"); 220 221 # octal constant 222 $x = 012345676543210123456765432101234567654321; 223 is($x, 224 "1736132869400711976876385488263403729", 225 "octal constant 012345676543210123456765432101234567654321"); 226 is(ref($x), $class, "value is a $class"); 227 228 # binary constant 229 $x = 0b01010100011001010110110001110011010010010110000101101101; 230 is($x, 231 "23755414508757357", 232 "binary constant 0b0101010001100101011011000111" 233 . "0011010010010110000101101101"); 234 is(ref($x), $class, "value is a $class"); 235} 236 237################################################################################ 238# The following tests are unique to $class. 239 240# These are handled by "float". 241 242$x = 0.999999999999999999999999999999999999999999999999999999999999999999999999; 243is($x, 244 "999999999999999999999999999999999999999999999999999999999999999999999999" . 245 "/1000000000000000000000000000000000000000000000000000000000000000000000000", 246 "decimal floating point literal 0." . ("9" x 72)); 247is(ref($x), $class, "value is a $class"); 248 249$x = 1e72 - 0.1; 250is($x, 251 "9999999999999999999999999999999999999999999999999999999999999999999999999" 252 . "/10", 253 "literal 1e72 - 0.1"); 254is(ref($x), $class, "value is a $class"); 255 256# These are handled by "float". 257 258SKIP: { 259 # Hexadecimal floating point literals require v5.28.0. 260 skip "perl v5.28.0 required for hexadecimal floating point literals", 261 "6" * "2" if $] < "5.028"; 262 263 for my $str (qw/ 0x1.92p+1 0X1.92P+1 264 0x1.92p1 0X1.92P1 265 0x19.2p-3 0X19.2P-3 /) 266 { 267 $x = eval $str; 268 is($x, "201/64", "hexadecimal floating point literal $str"); 269 is(ref($x), $class, "value is a $class"); 270 } 271} 272 273SKIP: { 274 # Octal floating point literals using the "0o" prefix require v5.34.0. 275 skip "perl v5.34.0 required for octal floating point literals" 276 . " with '0o' prefix", "6" * "2" if $] < "5.034"; 277 278 for my $str (qw/ 0o1.444p+1 0O1.444P+1 279 0o1.444p1 0O1.444P1 280 0o14.44p-2 0O14.44P-2 /) 281 { 282 $x = eval $str; 283 is($x, "201/64", "octal floating point literal $str"); 284 is(ref($x), $class, "value is a $class"); 285 } 286} 287 288SKIP: { 289 # Octal floating point literals using the "0" prefix require v5.32.0. 290 skip "perl v5.32.0 required for octal floating point literals", 291 "6" * "2" if $] < "5.032"; 292 293 for my $str (qw/ 01.444p+1 01.444P+1 294 01.444p1 01.444P1 295 014.44p-2 014.44P-2 /) 296 { 297 $x = eval $str; 298 is($x, "201/64", "octal floating point literal $str"); 299 is(ref($x), $class, "value is a $class"); 300 } 301} 302 303SKIP: { 304 # Binary floating point literals require v5.32.0. 305 skip "perl v5.32.0 required for binary floating point literals", 306 "6" * "2" if $] < "5.032"; 307 308 for my $str (qw/ 0b1.1001001p+1 0B1.1001001P+1 309 0b1.1001001p1 0B1.1001001P1 310 0b110.01001p-1 0B110.01001P-1 /) 311 { 312 $x = eval $str; 313 is($x, "201/64", "binary floating point literal $str"); 314 is(ref($x), $class, "value is a $class"); 315 } 316} 317 318is(1.0 / 3.0, "1/3", 319 "1.0 / 3.0 = 1/3"); 320