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 bignum; 27 28my $class = "Math::BigFloat"; 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"); 39like(ref($x), qr/^Math::BigInt(::Lite)?$/, 40 "value is a Math::BigInt or Math::BigInt::Lite"); 41 42SKIP: { 43 # Hexadecimal literals using the "0X" prefix require v5.14.0. 44 skip "perl v5.14.0 required for hexadecimal integer literals" 45 . " with '0X' prefix", "2" if $] < "5.014"; 46 47 $x = eval "0XFF"; 48 is($x, "255", "hexadecimal integer literal 0XFF"); 49 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 50 "value is a Math::BigInt or Math::BigInt::Lite"); 51} 52 53$x = 0377; 54is($x, "255", "octal integer literal 0377"); 55like(ref($x), qr/^Math::BigInt(::Lite)?$/, 56 "value is a Math::BigInt or Math::BigInt::Lite"); 57 58SKIP: { 59 # Octal literals using the "0o" prefix require v5.34.0. 60 skip "perl v5.34.0 required for octal floating point literals" 61 . " with '0o' prefix", "4" if $] < "5.034"; 62 63 for my $str (qw/ 0o377 0O377 /) { 64 $x = eval $str; 65 is($x, "255", "octal integer literal $str"); 66 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 67 "value is a Math::BigInt or Math::BigInt::Lite"); 68 } 69} 70 71$x = 0b11111111; 72is($x, "255", "binary integer literal 0b11111111"); 73like(ref($x), qr/^Math::BigInt(::Lite)?$/, 74 "value is a Math::BigInt or Math::BigInt::Lite"); 75 76SKIP: { 77 # Binary literals using the "0B" prefix require v5.14.0. 78 skip "perl v5.14.0 required for binary integer literals" 79 . " with '0B' prefix", "2" if $] < "5.014"; 80 81 $x = eval "0B11111111"; 82 is($x, "255", "binary integer literal 0B11111111"); 83 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 84 "value is a Math::BigInt or Math::BigInt::Lite"); 85} 86 87# These are handled by "float". 88 89$x = 999999999999999999999999999999999999999999999999999999999999999999999999; 90is($x, 91 "999999999999999999999999999999999999999999999999999999999999999999999999", 92 "decimal integer literal " . ("9" x 72)); 93like(ref($x), qr/^Math::BigInt(::Lite)?$/, 94 "value is a Math::BigInt or Math::BigInt::Lite"); 95 96$x = 1e72 - 1; 97is($x, 98 "999999999999999999999999999999999999999999999999999999999999999999999999", 99 "literal 1e72 - 1"); 100like(ref($x), qr/^Math::BigInt(::Lite)?$/, 101 "value is a Math::BigInt or Math::BigInt::Lite"); 102 103# These are handled by "float". 104 105SKIP: { 106 # Hexadecimal floating point literals require v5.28.0. 107 skip "perl v5.28.0 required for hexadecimal floating point literals", 108 "6" * "2" + "2" * "2" if $] < "5.028"; 109 110 for my $str (qw/ 0x1.3ap+8 0X1.3AP+8 111 0x1.3ap8 0X1.3AP8 112 0x13a0p-4 0X13A0P-4 /) 113 { 114 $x = eval $str; 115 is($x, "314", "hexadecimal floating point literal $str"); 116 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 117 "value is a Math::BigInt or Math::BigInt::Lite"); 118 } 119 120 for my $str (qw/ 0x0.0p+8 0X0.0P+8 /) 121 { 122 $x = eval $str; 123 is($x, "0", "hexadecimal floating point literal $str"); 124 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 125 "value is a Math::BigInt or Math::BigInt::Lite"); 126 } 127} 128 129SKIP: { 130 # Octal floating point literals using the "0o" prefix require v5.34.0. 131 skip "perl v5.34.0 required for octal floating point literals" 132 . " with '0o' prefix", "6" * "2" + "6" * "2" if $] < "5.034"; 133 134 for my $str (qw/ 0o1.164p+8 0O1.164P+8 135 0o1.164p8 0O1.164P8 136 0o11640p-4 0O11640P-4 /) 137 { 138 $x = eval $str; 139 is($x, "314", "octal floating point literal $str"); 140 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 141 "value is a Math::BigInt or Math::BigInt::Lite"); 142 } 143 144 for my $str (qw/ 0o0.0p+8 0O0.0P+8 145 0o0.0p8 0O0.0P8 146 0o0.0p-8 0O0.0P-8 /) 147 { 148 $x = eval $str; 149 is($x, "0", "octal floating point literal $str"); 150 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 151 "value is a Math::BigInt or Math::BigInt::Lite"); 152 } 153} 154 155SKIP: { 156 # Octal floating point literals using the "0" prefix require v5.32.0. 157 skip "perl v5.32.0 required for octal floating point literals", 158 "6" * "2" + "6" * "2" if $] < "5.032"; 159 160 for my $str (qw/ 01.164p+8 01.164P+8 161 01.164p8 01.164P8 162 011640p-4 011640P-4 /) 163 { 164 $x = eval $str; 165 is($x, "314", "octal floating point literal $str"); 166 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 167 "value is a Math::BigInt or Math::BigInt::Lite"); 168 } 169 170 for my $str (qw/ 00.0p+8 00.0P+8 171 00.0p8 00.0P8 172 00.0p-8 00.0P-8 /) 173 { 174 $x = eval $str; 175 is($x, "0", "octal floating point literal $str"); 176 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 177 "value is a Math::BigInt or Math::BigInt::Lite"); 178 } 179} 180 181SKIP: { 182 # Binary floating point literals require v5.32.0. 183 skip "perl v5.32.0 required for binary floating point literals", 184 "6" * "2" + "6" * "2" if $] < "5.032"; 185 186 for my $str (qw/ 0b1.0011101p+8 0B1.0011101P+8 187 0b1.0011101p8 0B1.0011101P8 188 0b10011101000p-2 0B10011101000P-2 /) 189 { 190 $x = eval $str; 191 is($x, "314", "binary floating point literal $str"); 192 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 193 "value is a Math::BigInt or Math::BigInt::Lite"); 194 } 195 196 for my $str (qw/ 0b0p+8 0B0P+8 197 0b0p8 0B0P8 198 0b0p-8 0B0P-8 199 /) 200 { 201 $x = eval $str; 202 is($x, "0", "binary floating point literal $str"); 203 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 204 "value is a Math::BigInt or Math::BigInt::Lite"); 205 } 206} 207 208# These are handled by "integer". 209 210$x = 314; 211is($x, "314", "integer literal 314"); 212like(ref($x), qr/^Math::BigInt(::Lite)?$/, 213 "value is a Math::BigInt or Math::BigInt::Lite"); 214 215$x = 0; 216is($x, "0", "integer literal 0"); 217like(ref($x), qr/^Math::BigInt(::Lite)?$/, 218 "value is a Math::BigInt or Math::BigInt::Lite"); 219 220$x = 2 ** 255; 221is($x, 222 "578960446186580977117854925043439539266" 223 . "34992332820282019728792003956564819968", 224 "2 ** 255"); 225like(ref($x), qr/^Math::BigInt(::Lite)?$/, 226 "value is a Math::BigInt or Math::BigInt::Lite"); 227 228# These are handled by "binary". 229 230{ 231 no warnings "portable"; # protect against "non-portable" warnings 232 233 # hexadecimal constant 234 $x = 0x123456789012345678901234567890; 235 is($x, 236 "94522879687365475552814062743484560", 237 "hexadecimal constant 0x123456789012345678901234567890"); 238 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 239 "value is a Math::BigInt or Math::BigInt::Lite"); 240 241 # octal constant 242 $x = 012345676543210123456765432101234567654321; 243 is($x, 244 "1736132869400711976876385488263403729", 245 "octal constant 012345676543210123456765432101234567654321"); 246 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 247 "value is a Math::BigInt or Math::BigInt::Lite"); 248 249 # binary constant 250 $x = 0b01010100011001010110110001110011010010010110000101101101; 251 is($x, 252 "23755414508757357", 253 "binary constant 0b0101010001100101011011000111" 254 . "0011010010010110000101101101"); 255 like(ref($x), qr/^Math::BigInt(::Lite)?$/, 256 "value is a Math::BigInt or Math::BigInt::Lite"); 257} 258 259################################################################################ 260# The following tests are unique to $class. 261 262# These are handled by "float". 263 264$x = 0.999999999999999999999999999999999999999999999999999999999999999999999999; 265is($x, 266 "0.999999999999999999999999999999999999999999999999999999999999999999999999", 267 "decimal floating point literal 0." . ("9" x 72)); 268is(ref($x), $class, "value is a $class"); 269 270$x = 1e72 - 0.1; 271is($x, 272 "999999999999999999999999999999999999999999999999999999999999999999999999.9", 273 "literal 1e72 - 0.1"); 274is(ref($x), $class, "value is a $class"); 275 276# These are handled by "float". 277 278SKIP: { 279 # Hexadecimal floating point literals require v5.28.0. 280 skip "perl v5.22.0 required for hexadecimal floating point literals", 281 "6" * "2" if $] < "5.028"; 282 283 for my $str (qw/ 0x1.92p+1 0X1.92P+1 284 0x1.92p1 0X1.92P1 285 0x19.2p-3 0X19.2P-3 /) 286 { 287 $x = eval $str; 288 is($x, "3.140625", "hexadecimal floating point literal $str"); 289 is(ref($x), $class, "value is a $class"); 290 } 291} 292 293SKIP: { 294 # Octal floating point literals using the "0o" prefix require v5.34.0. 295 skip "perl v5.34.0 required for octal floating point literals" 296 . " with '0o' prefix", "6" * "2" if $] < "5.034"; 297 298 for my $str (qw/ 0o1.444p+1 0O1.444P+1 299 0o1.444p1 0O1.444P1 300 0o14.44p-2 0O14.44P-2 /) 301 { 302 $x = eval $str; 303 is($x, "3.140625", "octal floating point literal $str"); 304 is(ref($x), $class, "value is a $class"); 305 } 306} 307 308SKIP: { 309 # Octal floating point literals using the "0" prefix require v5.32.0. 310 skip "perl v5.32.0 required for octal floating point literals", 311 "6" * "2" if $] < "5.032"; 312 313 for my $str (qw/ 01.444p+1 01.444P+1 314 01.444p1 01.444P1 315 014.44p-2 014.44P-2 /) 316 { 317 $x = eval $str; 318 is($x, "3.140625", "octal floating point literal $str"); 319 is(ref($x), $class, "value is a $class"); 320 } 321} 322 323SKIP: { 324 # Binary floating point literals require v5.32.0. 325 skip "perl v5.32.0 required for binary floating point literals", 326 "6" * "2" if $] < "5.032"; 327 328 for my $str (qw/ 0b1.1001001p+1 0B1.1001001P+1 329 0b1.1001001p1 0B1.1001001P1 330 0b110.01001p-1 0B110.01001P-1 /) 331 { 332 $x = eval $str; 333 is($x, "3.140625", "binary floating point literal $str"); 334 is(ref($x), $class, "value is a $class"); 335 } 336} 337 338is(1.0 / 3.0, "0.3333333333333333333333333333333333333333", 339 "1.0 / 3.0 = 0.3333333333333333333333333333333333333333"); 340