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