ref: 1019b884273ecfba87c33205a50084981820376f
parent: 4acb5822344f2dc7dc360720ef803e1d36d2e927
author: S. Gilles <sgilles@math.umd.edu>
date: Fri Jul 20 04:25:54 EDT 2018
Ensure tan(NaN) is a [q]NaN.
--- a/lib/math/tan-impl.myr
+++ b/lib/math/tan-impl.myr
@@ -382,8 +382,15 @@
}
const tanorcot = {x : flt64, want_tan : bool
+ var e : int64
+ (_, e, _) = std.flt64explode(x)
+ if e == 1024
+ -> (std.flt64nan(), 0.0)
+ ;;
+
var N : int64
var x1 : flt64, x2 : flt64
+
(N, x1, x2) = trig_reduce(x)
var then_negate : bool = false
--- /dev/null
+++ b/lib/math/test/tan-impl.myr
@@ -1,0 +1,152 @@
+use std
+use math
+use testr
+
+const main = {
+ math.fptrap(false)
+ testr.run([
+ [.name="tan-cot-01", .fn = tancot01], /* flt32 */
+ [.name="tan-cot-02", .fn = tancot02], /* flt64 */
+ [.name="tan-cot-03", .fn = tancot03], /* off-by-1-ulp quarantine */
+ [.name="tan-cot-04", .fn = tancot04], /* exhaustively test C */
+ [.name="tan-cot-05", .fn = tancot05], /* NaN handling */
+ ][:])
+}
+
+const same32 = {a, b
+ if a == b
+ -> true
+ ;;
+
+ if std.isnan(std.flt32frombits(a)) && std.isnan(std.flt32frombits(b))
+ -> true
+ ;;
+
+ -> false
+}
+
+const same64 = {a, b
+ if a == b
+ -> true
+ ;;
+
+ if std.isnan(std.flt64frombits(a)) && std.isnan(std.flt64frombits(b))
+ -> true
+ ;;
+
+ -> false
+}
+
+const tancot01 = {c
+ var inputs : (uint32, uint32, uint32)[:] = [
+ (0x00000000, 0x00000000, 0x7f800000),
+ ][:]
+
+ for (x, yt, yc) : inputs
+ var xf : flt32 = std.flt32frombits(x)
+ var rtf, rcf
+ rtf = math.tan(xf)
+ rcf = math.cot(xf)
+
+ var rtu = std.flt32bits(rtf)
+ var rcu = std.flt32bits(rcf)
+
+ testr.check(c, same32(rtu, yt),
+ "tan(0x{b=16,w=8,p=0}) should be 0x{b=16,w=8,p=0}, was 0x{b=16,w=8,p=0}",
+ x, yt, rtu)
+
+ testr.check(c, same32(rcu, yc),
+ "cot(0x{b=16,w=8,p=0}) should be 0x{b=16,w=8,p=0}, was 0x{b=16,w=8,p=0}",
+ x, yc, rcu)
+ ;;
+}
+
+const tancot02 = {c
+ var inputs : (uint64, uint64, uint64)[:] = [
+ (0x0000000000000000, 0x0000000000000000, 0x7ff0000000000000),
+ (0x41bb951f1572eba5, 0xbc8f54f5227a4e84, 0x3ff0000000000000), /* [GB91]'s "Xhard" */
+ ][:]
+
+ for (x, yt, yc) : inputs
+ var xf : flt64 = std.flt64frombits(x)
+ var rtf, rcf
+ rtf = math.tan(xf)
+ rcf = math.cot(xf)
+
+ var rtu = std.flt64bits(rtf)
+ var rcu = std.flt64bits(rcf)
+
+ testr.check(c, same64(rtu, yt),
+ "tan(0x{b=16,w=16,p=0}) should be 0x{b=16,w=16,p=0}, was 0x{b=16,w=16,p=0}",
+ x, yt, rtu)
+
+ testr.check(c, same64(rcu, yc),
+ "cot(0x{b=16,w=16,p=0}) should be (0x{b=16,w=16,p=0}, 0x{b=16,w=16,p=0}), was (0x{b=16,w=16,p=0}, 0x{b=16,w=16,p=0})",
+ x, yc, rcu)
+ ;;
+}
+
+const tancot03 = {c
+ var inputs : (uint64, uint64, uint64, uint64, uint64)[:] = [
+ (0x5101000000000000, 0x3fe9706123d509f1, 0xbfe369af9695aba1, 0x3fe9706123d509f0, 0xbfe369af9695aba0),
+ (0xf83b13a6a142b6d5, 0xbf5a86f4edeb02f2, 0x3feffffd404efc20, 0xbf5a86f4edeb02f1, 0x3feffffd404efc20),
+ (0x4b01000000000000, 0xbfe3e9527dc75f12, 0x3fe90cf80997c963, 0xbfe3e9527dc75f13, 0x3fe90cf80997c964),
+ ][:]
+
+ for (x, yt_perfect, yc_perfect, yt_acceptable, yc_acceptable) : inputs
+ var xf : flt64 = std.flt64frombits(x)
+ var rtf, rcf
+ rtf = math.tan(xf)
+ rcf = math.cot(xf)
+
+ var rtu = std.flt64bits(rtf)
+ var rcu = std.flt64bits(rcf)
+
+ testr.check(c, (same64(rtu, yt_perfect) || same64(rtu, yt_acceptable)),
+ "tan(0x{b=16,w=16,p=0}) should be 0x{b=16,w=16,p=0}, will also accept 0x{b=16,w=16,p=0}, was 0x{b=16,w=16,p=0}",
+ x, yt_perfect, yt_acceptable, rtu)
+
+ testr.check(c, (same64(rcu, yc_perfect) || same64(rcu, yc_acceptable)),
+ "tan(0x{b=16,w=16,p=0}) should be 0x{b=16,w=16,p=0}, will also accept 0x{b=16,w=16,p=0}, was 0x{b=16,w=16,p=0}",
+ x, yc_perfect, yc_acceptable, rcu)
+ ;;
+}
+
+const tancot04 = {c
+ /*
+ There should be one of these for each j, each corresponding
+ to the appropriate xi. This should ensure that, when
+ upgrading the C tables, things don't get too terribly
+ broken.
+ */
+ var inputs : (uint64, uint64, uint64)[:] = [
+ ][:]
+
+ testr.fail(c, "You need to fill out the 256 C entries in tancot04")
+
+ for (x, yt, yc) : inputs
+ var xf : flt64 = std.flt64frombits(x)
+ var rtf, rcf
+ rtf = math.tan(xf)
+ rcf = math.cot(xf)
+
+ var rtu = std.flt64bits(rtf)
+ var rcu = std.flt64bits(rcf)
+
+ testr.check(c, same64(rtu, yt),
+ "tan(0x{b=16,w=16,p=0}) should be 0x{b=16,w=16,p=0}, was 0x{b=16,w=16,p=0}",
+ x, yt, rtu)
+
+ testr.check(c, same64(rcu, yc),
+ "cot(0x{b=16,w=16,p=0}) should be (0x{b=16,w=16,p=0}, 0x{b=16,w=16,p=0}), was (0x{b=16,w=16,p=0}, 0x{b=16,w=16,p=0})",
+ x, yc, rcu)
+ ;;
+
+}
+
+const tancot05 = {c
+ testr.check(c, std.isnan(math.cot(std.flt64nan())), "cot(NaN64) should be NaN")
+ testr.check(c, std.isnan(math.tan(std.flt64nan())), "tan(NaN64) should be NaN")
+ testr.check(c, std.isnan(math.cot(std.flt32nan())), "cot(NaN32) should be NaN")
+ testr.check(c, std.isnan(math.tan(std.flt32nan())), "tan(NaN32) should be NaN")
+}