1850e2753Smillert#!perl -w 2850e2753Smillert 3850e2753Smillertuse strict; 4850e2753Smillert 5b8851fccSafresh1use POSIX ':math_h_c99'; 6b8851fccSafresh1use POSIX ':nan_payload'; 7898184e3Ssthenuse Test::More; 8850e2753Smillert 9b8851fccSafresh1use Config; 10b8851fccSafresh1 11898184e3Ssthen# These tests are mainly to make sure that these arithmetic functions 12850e2753Smillert# exist and are accessible. They are not meant to be an exhaustive 13850e2753Smillert# test for the interface. 14850e2753Smillert 15898184e3Ssthensub between { 16898184e3Ssthen my ($low, $have, $high, $desc) = @_; 17898184e3Ssthen local $Test::Builder::Level = $Test::Builder::Level + 1; 18898184e3Ssthen 19898184e3Ssthen cmp_ok($have, '>=', $low, $desc); 20898184e3Ssthen cmp_ok($have, '<=', $high, $desc); 21898184e3Ssthen} 22898184e3Ssthen 23850e2753Smillertis(acos(1), 0, "Basic acos(1) test"); 24898184e3Ssthenbetween(3.14, acos(-1), 3.15, 'acos(-1)'); 25898184e3Ssthenbetween(1.57, acos(0), 1.58, 'acos(0)'); 26850e2753Smillertis(asin(0), 0, "Basic asin(0) test"); 27898184e3Ssthencmp_ok(asin(1), '>', 1.57, "Basic asin(1) test"); 28898184e3Ssthencmp_ok(asin(-1), '<', -1.57, "Basic asin(-1) test"); 29898184e3Ssthencmp_ok(asin(1), '==', -asin(-1), 'asin(1) == -asin(-1)'); 30850e2753Smillertis(atan(0), 0, "Basic atan(0) test"); 31898184e3Ssthenbetween(0.785, atan(1), 0.786, 'atan(1)'); 32898184e3Ssthenbetween(-0.786, atan(-1), -0.785, 'atan(-1)'); 33898184e3Ssthencmp_ok(atan(1), '==', -atan(-1), 'atan(1) == -atan(-1)'); 34850e2753Smillertis(cosh(0), 1, "Basic cosh(0) test"); 35898184e3Ssthenbetween(1.54, cosh(1), 1.55, 'cosh(1)'); 36898184e3Ssthenbetween(1.54, cosh(-1), 1.55, 'cosh(-1)'); 37898184e3Ssthenis(cosh(1), cosh(-1), 'cosh(1) == cosh(-1)'); 38850e2753Smillertis(floor(1.23441242), 1, "Basic floor(1.23441242) test"); 39898184e3Ssthenis(floor(-1.23441242), -2, "Basic floor(-1.23441242) test"); 40850e2753Smillertis(fmod(3.5, 2.0), 1.5, "Basic fmod(3.5, 2.0) test"); 41850e2753Smillertis(join(" ", frexp(1)), "0.5 1", "Basic frexp(1) test"); 42850e2753Smillertis(ldexp(0,1), 0, "Basic ldexp(0,1) test"); 43850e2753Smillertis(log10(1), 0, "Basic log10(1) test"); 44850e2753Smillertis(log10(10), 1, "Basic log10(10) test"); 45850e2753Smillertis(join(" ", modf(1.76)), "0.76 1", "Basic modf(1.76) test"); 46850e2753Smillertis(sinh(0), 0, "Basic sinh(0) test"); 47898184e3Ssthenbetween(1.17, sinh(1), 1.18, 'sinh(1)'); 48898184e3Ssthenbetween(-1.18, sinh(-1), -1.17, 'sinh(-1)'); 49850e2753Smillertis(tan(0), 0, "Basic tan(0) test"); 50898184e3Ssthenbetween(1.55, tan(1), 1.56, 'tan(1)'); 51898184e3Ssthenbetween(1.55, tan(1), 1.56, 'tan(-1)'); 52898184e3Ssthencmp_ok(tan(1), '==', -tan(-1), 'tan(1) == -tan(-1)'); 53850e2753Smillertis(tanh(0), 0, "Basic tanh(0) test"); 54898184e3Ssthenbetween(0.76, tanh(1), 0.77, 'tanh(1)'); 55898184e3Ssthenbetween(-0.77, tanh(-1), -0.76, 'tanh(-1)'); 56898184e3Ssthencmp_ok(tanh(1), '==', -tanh(-1), 'tanh(1) == -tanh(-1)'); 57898184e3Ssthen 58b8851fccSafresh1SKIP: { 59b8851fccSafresh1 skip "no fpclassify", 4 unless $Config{d_fpclassify}; 60b8851fccSafresh1 is(fpclassify(1), FP_NORMAL, "fpclassify 1"); 61b8851fccSafresh1 is(fpclassify(0), FP_ZERO, "fpclassify 0"); 629f11ffb7Safresh1 SKIP: { 639f11ffb7Safresh1 skip("no inf", 1) unless $Config{d_double_has_inf}; 64b8851fccSafresh1 is(fpclassify(INFINITY), FP_INFINITE, "fpclassify INFINITY"); 659f11ffb7Safresh1 } 669f11ffb7Safresh1 SKIP: { 679f11ffb7Safresh1 skip("no nan", 1) unless $Config{d_double_has_nan}; 68b8851fccSafresh1 is(fpclassify(NAN), FP_NAN, "fpclassify NAN"); 69b8851fccSafresh1 } 709f11ffb7Safresh1} 71b8851fccSafresh1 72b8851fccSafresh1sub near { 73b8851fccSafresh1 my ($got, $want, $msg, $eps) = @_; 74b8851fccSafresh1 $eps ||= 1e-6; 75b8851fccSafresh1 cmp_ok(abs($got - $want), '<', $eps, $msg); 76b8851fccSafresh1} 77b8851fccSafresh1 78b8851fccSafresh1SKIP: { 79b46d8ef2Safresh1 80b8851fccSafresh1 unless ($Config{d_acosh}) { 81b8851fccSafresh1 skip "no acosh, suspecting no C99 math"; 82b8851fccSafresh1 } 83b46d8ef2Safresh1 if ($^O =~ /VMS/) { 84b8851fccSafresh1 skip "running in $^O, C99 math support uneven"; 85b8851fccSafresh1 } 86b46d8ef2Safresh1 87b8851fccSafresh1 near(M_SQRT2, 1.4142135623731, "M_SQRT2", 1e-9); 88b8851fccSafresh1 near(M_E, 2.71828182845905, "M_E", 1e-9); 89b8851fccSafresh1 near(M_PI, 3.14159265358979, "M_PI", 1e-9); 90b8851fccSafresh1 near(acosh(2), 1.31695789692482, "acosh", 1e-9); 91b8851fccSafresh1 near(asinh(1), 0.881373587019543, "asinh", 1e-9); 92b8851fccSafresh1 near(atanh(0.5), 0.549306144334055, "atanh", 1e-9); 93b8851fccSafresh1 near(cbrt(8), 2, "cbrt", 1e-9); 94b8851fccSafresh1 near(cbrt(-27), -3, "cbrt", 1e-9); 95b8851fccSafresh1 near(copysign(3.14, -2), -3.14, "copysign", 1e-9); 96b8851fccSafresh1 near(expm1(2), 6.38905609893065, "expm1", 1e-9); 97b8851fccSafresh1 near(expm1(1e-6), 1.00000050000017e-06, "expm1", 1e-9); 98b8851fccSafresh1 is(fdim(12, 34), 0, "fdim 12 34"); 99b8851fccSafresh1 is(fdim(34, 12), 22, "fdim 34 12"); 100b8851fccSafresh1 is(fmax(12, 34), 34, "fmax 12 34"); 101b8851fccSafresh1 is(fmin(12, 34), 12, "fmin 12 34"); 102b8851fccSafresh1 is(hypot(3, 4), 5, "hypot 3 4"); 103b8851fccSafresh1 near(hypot(-2, 1), sqrt(5), "hypot -1 2", 1e-9); 104b8851fccSafresh1 is(ilogb(255), 7, "ilogb 255"); 105b8851fccSafresh1 is(ilogb(256), 8, "ilogb 256"); 106b8851fccSafresh1 ok(isfinite(1), "isfinite 1"); 1079f11ffb7Safresh1 ok(!isinf(42), "isinf 42"); 1089f11ffb7Safresh1 ok(!isnan(42), "isnan Inf"); 1099f11ffb7Safresh1 SKIP: { 110eac174f2Safresh1 skip("no inf", 3) unless $Config{d_double_has_inf}; 111b8851fccSafresh1 ok(!isfinite(Inf), "isfinite Inf"); 112b8851fccSafresh1 ok(isinf(Inf), "isinf Inf"); 1139f11ffb7Safresh1 ok(!isnan(Inf), "isnan Inf"); 1149f11ffb7Safresh1 } 1159f11ffb7Safresh1 SKIP: { 116eac174f2Safresh1 skip("no nan", 4) unless $Config{d_double_has_nan}; 1179f11ffb7Safresh1 ok(!isfinite(NaN), "isfinite NaN"); 118b8851fccSafresh1 ok(!isinf(NaN), "isinf NaN"); 119b8851fccSafresh1 ok(isnan(NaN), "isnan NaN"); 120b8851fccSafresh1 cmp_ok(nan(), '!=', nan(), 'nan'); 1219f11ffb7Safresh1 } 122b8851fccSafresh1 near(log1p(2), 1.09861228866811, "log1p", 1e-9); 123b8851fccSafresh1 near(log1p(1e-6), 9.99999500000333e-07, "log1p", 1e-9); 124b8851fccSafresh1 near(log2(8), 3, "log2", 1e-9); 125b8851fccSafresh1 is(signbit(2), 0, "signbit 2"); # zero 126b8851fccSafresh1 ok(signbit(-2), "signbit -2"); # non-zero 1279f11ffb7Safresh1 is(signbit(0), 0, "signbit 0"); # zero 1289f11ffb7Safresh1 is(signbit(0.5), 0, "signbit 0.5"); # zero 1299f11ffb7Safresh1 ok(signbit(-0.5), "signbit -0.5"); # non-zero 130b8851fccSafresh1 is(round(2.25), 2, "round 2.25"); 131b8851fccSafresh1 is(round(-2.25), -2, "round -2.25"); 132b8851fccSafresh1 is(round(2.5), 3, "round 2.5"); 133b8851fccSafresh1 is(round(-2.5), -3, "round -2.5"); 134b8851fccSafresh1 is(round(2.75), 3, "round 2.75"); 135b8851fccSafresh1 is(round(-2.75), -3, "round 2.75"); 1369f11ffb7Safresh1 is(lround(-2.75), -3, "lround -2.75"); 1379f11ffb7Safresh1 is(lround(-0.25), 0, "lround -0.25"); 1389f11ffb7Safresh1 is(lround(-0.50), -1, "lround -0.50"); 1399f11ffb7Safresh1 is(signbit(lround(-0.25)), 0, "signbit lround -0.25 zero"); 1409f11ffb7Safresh1 ok(signbit(lround(-0.50)), "signbit lround -0.50 non-zero"); # non-zero 141b8851fccSafresh1 is(trunc(2.25), 2, "trunc 2.25"); 142b8851fccSafresh1 is(trunc(-2.25), -2, "trunc -2.25"); 143b8851fccSafresh1 is(trunc(2.5), 2, "trunc 2.5"); 144b8851fccSafresh1 is(trunc(-2.5), -2, "trunc -2.5"); 145b8851fccSafresh1 is(trunc(2.75), 2, "trunc 2.75"); 146b8851fccSafresh1 is(trunc(-2.75), -2, "trunc -2.75"); 147b8851fccSafresh1 ok(isless(1, 2), "isless 1 2"); 148b8851fccSafresh1 ok(!isless(2, 1), "isless 2 1"); 149b8851fccSafresh1 ok(!isless(1, 1), "isless 1 1"); 150b8851fccSafresh1 ok(isgreater(2, 1), "isgreater 2 1"); 151b8851fccSafresh1 ok(islessequal(1, 1), "islessequal 1 1"); 1529f11ffb7Safresh1 1539f11ffb7Safresh1 SKIP: { 1549f11ffb7Safresh1 skip("no nan", 2) unless $Config{d_double_has_nan}; 1559f11ffb7Safresh1 ok(!isless(1, NaN), "isless 1 NaN"); 156b8851fccSafresh1 ok(isunordered(1, NaN), "isunordered 1 NaN"); 1579f11ffb7Safresh1 } 158b8851fccSafresh1 159b8851fccSafresh1 near(erf(0.5), 0.520499877813047, "erf 0.5", 1.5e-7); 160b8851fccSafresh1 near(erf(1), 0.842700792949715, "erf 1", 1.5e-7); 161b8851fccSafresh1 near(erf(9), 1, "erf 9", 1.5e-7); 162b8851fccSafresh1 near(erfc(0.5), 0.479500122186953, "erfc 0.5", 1.5e-7); 163b8851fccSafresh1 near(erfc(1), 0.157299207050285, "erfc 1", 1.5e-7); 164b8851fccSafresh1 near(erfc(9), 0, "erfc 9", 1.5e-7); 165b8851fccSafresh1 166b8851fccSafresh1 # tgamma(n) = (n - 1)! 167b8851fccSafresh1 # lgamma(n) = log(tgamma(n)) 168b8851fccSafresh1 near(tgamma(5), 24, "tgamma 5", 1.5e-7); 169b8851fccSafresh1 near(tgamma(5.5), 52.3427777845535, "tgamma 5.5", 1.5e-7); 170b8851fccSafresh1 near(tgamma(9), 40320, "tgamma 9", 1.5e-7); 171b8851fccSafresh1 near(lgamma(5), 3.17805383034795, "lgamma 4", 1.5e-7); 172b8851fccSafresh1 near(lgamma(5.5), 3.95781396761872, "lgamma 5.5", 1.5e-7); 173b8851fccSafresh1 near(lgamma(9), 10.6046029027452, "lgamma 9", 1.5e-7); 174b8851fccSafresh1 1759f11ffb7Safresh1 SKIP: { 1769f11ffb7Safresh1 skip("no inf/nan", 19) unless $Config{d_double_has_inf} && $Config{d_double_has_nan}; 1779f11ffb7Safresh1 1789f11ffb7Safresh1 # These don't work on old mips/hppa platforms 1799f11ffb7Safresh1 # because nan with payload zero == Inf (or == -Inf). 180b8851fccSafresh1 # ok(isnan(setpayload(0)), "setpayload zero"); 181b8851fccSafresh1 # is(getpayload(setpayload(0)), 0, "setpayload + getpayload (zero)"); 182b8851fccSafresh1 # 183b8851fccSafresh1 # These don't work on most platforms because == Inf (or == -Inf). 184b8851fccSafresh1 # ok(isnan(setpayloadsig(0)), "setpayload zero"); 185b8851fccSafresh1 # is(getpayload(setpayloadsig(0)), 0, "setpayload + getpayload (zero)"); 186b8851fccSafresh1 187b8851fccSafresh1 # Verify that the payload set be setpayload() 188b8851fccSafresh1 # (1) still is a nan 189b8851fccSafresh1 # (2) but the payload can be retrieved 190b8851fccSafresh1 # (3) but is not signaling 191b8851fccSafresh1 my $x = 0; 192b8851fccSafresh1 setpayload($x, 0x12345); 193b8851fccSafresh1 ok(isnan($x), "setpayload + isnan"); 194b8851fccSafresh1 is(getpayload($x), 0x12345, "setpayload + getpayload"); 195b8851fccSafresh1 ok(!issignaling($x), "setpayload + issignaling"); 196b8851fccSafresh1 197b8851fccSafresh1 # Verify that the signaling payload set be setpayloadsig() 198b8851fccSafresh1 # (1) still is a nan 199b8851fccSafresh1 # (2) but the payload can be retrieved 200b8851fccSafresh1 # (3) and is signaling 201b8851fccSafresh1 setpayloadsig($x, 0x12345); 202b8851fccSafresh1 ok(isnan($x), "setpayloadsig + isnan"); 203b8851fccSafresh1 is(getpayload($x), 0x12345, "setpayloadsig + getpayload"); 204b8851fccSafresh1 SKIP: { 205b8851fccSafresh1 # https://rt.perl.org/Ticket/Display.html?id=125710 206b8851fccSafresh1 # In the 32-bit x86 ABI cannot preserve the signaling bit 207b8851fccSafresh1 # (the x87 simply does not preserve that). But using the 208b8851fccSafresh1 # 80-bit extended format aka long double, the bit is preserved. 209b8851fccSafresh1 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57484 210b8851fccSafresh1 my $could_be_x86_32 = 211b8851fccSafresh1 # This is a really weak test: there are other 32-bit 212b8851fccSafresh1 # little-endian platforms than just Intel (some embedded 213b8851fccSafresh1 # processors, for example), but we use this just for not 214b8851fccSafresh1 # bothering with the test if things look iffy. 215b8851fccSafresh1 # We could, say, $Config{ccsymbols} =~ /\b__[xi][3-7]86=1\b/, 216b8851fccSafresh1 # but that feels quite shaky. 217b8851fccSafresh1 $Config{byteorder} =~ /1234/ && 218b8851fccSafresh1 $Config{longdblkind} == 3 && 219b8851fccSafresh1 $Config{ptrsize} == 4; 220b8851fccSafresh1 skip($^O, 1) if $could_be_x86_32 && !$Config{uselongdouble}; 221b8851fccSafresh1 ok(issignaling($x), "setpayloadsig + issignaling"); 222b8851fccSafresh1 } 223b8851fccSafresh1 224b8851fccSafresh1 # Try a payload more than one byte. 225b8851fccSafresh1 is(getpayload(nan(0x12345)), 0x12345, "nan + getpayload"); 226b8851fccSafresh1 227b8851fccSafresh1 # Try payloads of 2^k, most importantly at and beyond 2^32. These 228b8851fccSafresh1 # tests will fail if NV is just 32-bit float, but that Should Not 229b8851fccSafresh1 # Happen (tm). 230b8851fccSafresh1 is(getpayload(nan(2**31)), 2**31, "nan + getpayload 2**31"); 231b8851fccSafresh1 is(getpayload(nan(2**32)), 2**32, "nan + getpayload 2**32"); 232b8851fccSafresh1 is(getpayload(nan(2**33)), 2**33, "nan + getpayload 2**33"); 233b8851fccSafresh1 234b8851fccSafresh1 # Payloads just lower than 2^k. 235b8851fccSafresh1 is(getpayload(nan(2**31-1)), 2**31-1, "nan + getpayload 2**31-1"); 236b8851fccSafresh1 is(getpayload(nan(2**32-1)), 2**32-1, "nan + getpayload 2**32-1"); 237b8851fccSafresh1 238b8851fccSafresh1 # Payloads not divisible by two (and larger than 2**32). 239b8851fccSafresh1 240b8851fccSafresh1 SKIP: { 241b8851fccSafresh1 # solaris gets 10460353202 from getpayload() when it should 242b8851fccSafresh1 # get 10460353203 (the 3**21). Things go wrong already in 243b8851fccSafresh1 # the nan() payload setting: [0x2, 0x6f7c52b4] (ivsize=4) 244b8851fccSafresh1 # instead [0x2, 0x6f7c52b3]. Then at getpayload() things 245b8851fccSafresh1 # go wrong again, now in other direction: with the (wrong) 246b8851fccSafresh1 # [0x2, 0x6f7c52b4] encoded in the nan we should decode into 247b8851fccSafresh1 # 10460353204, but we get 10460353202. It doesn't seem to 248b8851fccSafresh1 # help even if we use 'unsigned long long' instead of UV/U32 249b8851fccSafresh1 # in the POSIX.xs:S_setpayload/S_getpayload. 250b8851fccSafresh1 # 251b8851fccSafresh1 # casting bug? fmod() bug? Though also broken with 252b8851fccSafresh1 # -Duselongdouble + fmodl(), so maybe Solaris cc bug 253b8851fccSafresh1 # in general? 254b8851fccSafresh1 # 255b8851fccSafresh1 # Ironically, the large prime seems to work even in Solaris, 256b8851fccSafresh1 # probably just by blind luck. 257b8851fccSafresh1 skip($^O, 1) if $^O eq 'solaris'; 258b8851fccSafresh1 is(getpayload(nan(3**21)), 3**21, "nan + getpayload 3**21"); 259b8851fccSafresh1 } 260b8851fccSafresh1 is(getpayload(nan(4294967311)), 4294967311, "nan + getpayload prime"); 261b8851fccSafresh1 262b8851fccSafresh1 # Truncates towards zero. 263b8851fccSafresh1 is(getpayload(nan(1234.567)), 1234, "nan (trunc) + getpayload"); 264b8851fccSafresh1 265b8851fccSafresh1 # Not signaling. 266b8851fccSafresh1 ok(!issignaling(0), "issignaling zero"); 267b8851fccSafresh1 ok(!issignaling(+Inf), "issignaling +Inf"); 268b8851fccSafresh1 ok(!issignaling(-Inf), "issignaling -Inf"); 269b8851fccSafresh1 ok(!issignaling(NaN), "issignaling NaN"); 2709f11ffb7Safresh1 } 271b8851fccSafresh1} # SKIP 272b8851fccSafresh1 273eac174f2Safresh1SKIP: { 274eac174f2Safresh1 skip('no INFINITY', 4) unless defined &INFINITY; 275eac174f2Safresh1 # Note that if INFINITY were a bareword, it would be numified to +Inf, 276eac174f2Safresh1 # which might confuse following tests. 277eac174f2Safresh1 # But this cannot happen as long as "use strict" is effective. 278eac174f2Safresh1 ok(isinf(INFINITY), "isinf INFINITY"); 279eac174f2Safresh1 is(INFINITY, 'Inf', "INFINITY is Perl's Inf"); 280eac174f2Safresh1 cmp_ok(INFINITY, '>', ($Config{uselongdouble} ? POSIX::LDBL_MAX : POSIX::DBL_MAX), 281eac174f2Safresh1 "INFINITY > DBL_MAX"); 282eac174f2Safresh1 ok(!signbit(INFINITY), "signbit(INFINITY)"); 283eac174f2Safresh1} 284eac174f2Safresh1 285eac174f2Safresh1SKIP: { 286eac174f2Safresh1 skip('no NAN', 5) unless defined &NAN; 287eac174f2Safresh1 ok(isnan(NAN()), "isnan NAN"); 288eac174f2Safresh1 # Using like() rather than is() is to deal with non-zero payload 289eac174f2Safresh1 # (currently this is not the case, but someday Perl might stringify it...) 290eac174f2Safresh1 like(NAN, qr/^NaN/, "NAN is Perl's NaN"); 291eac174f2Safresh1 cmp_ok(NAN, '!=', NAN, "NAN != NAN"); 292eac174f2Safresh1 ok(!(NAN == NAN), "NAN == NAN"); 293*3d61058aSafresh1 # we have a fallback copysign(), but it doesn't work for NaN 294*3d61058aSafresh1 skip('no copysign', 2) unless $Config{d_copysign}; 295*3d61058aSafresh1 ok(!signbit(copysign(NAN, 1.0)), "signbit(copysign(NAN, 1.0)))"); 296*3d61058aSafresh1 ok(signbit(copysign(NAN, -1.0)), "signbit(copysign(NAN, -1.0)))"); 297eac174f2Safresh1} 298eac174f2Safresh1 299898184e3Ssthendone_testing(); 300