shithub: mc

ref: 4aa0e6c6b8a1a23b144b0382d6156aaa55b2c7fd
dir: /lib/math/test/exp-impl.myr/

View raw version
use std
use math
use testr

/*
   Note: a major part of the algorithms are the S constants. They
   are tested extensively in expm101 and expm102.
 */
const main = {
	math.fptrap(false)
	testr.run([
		[.name="exp-01", .fn = exp01],
		[.name="exp-02", .fn = exp02],
		[.name="exp-03", .fn = exp03],
		[.name="exp-04", .fn = exp04],
		[.name="expm1-01", .fn = expm101],
		[.name="expm1-02", .fn = expm102],
		[.name="expm1-03", .fn = expm103],
		[.name="expm1-04", .fn = expm104],
	][:])
}

const exp01 = {c
	var inputs : (uint32, uint32)[:] = [
		(0x00000000, 0x3f800000),
		(0x34000000, 0x3f800001),
		(0x3c000000, 0x3f810101),
		(0x42000000, 0x568fa1fe),
		(0xc2b00000, 0x0041edc4),
		(0xc2b20000, 0x001840fc),
		(0x7f7fffff, 0x7f800000),
		(0x7f800000, 0x7f800000),
		(0x7f800001, 0x7fc00000),
		(0xc2cff1b3, 0x00000001),
		(0xc2cff1b4, 0x00000001),
		(0xc2cff1b5, 0000000000),
		(0x42b17217, 0x7f7fff84),
		(0x42b17218, 0x7f800000),
		(0x42b17219, 0x7f800000),
	][:]

	for (x, y) : inputs
		var xf : flt32 = std.flt32frombits(x)
		var yf : flt32 = std.flt32frombits(y)
		var rf = math.exp(xf)
		testr.check(c, rf == yf,
			"exp(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, y, std.flt32bits(rf))
	;;
}

const exp02 = {c
	var inputs : (uint64, uint64)[:] = [
		(0x0000000000000000, 0x3ff0000000000000),
		(0x3e50000000000000, 0x3ff0000004000000),
	][:]

	for (x, y) : inputs
		var xf : flt64 = std.flt64frombits(x)
		var yf : flt64 = std.flt64frombits(y)
		var rf = math.exp(xf)
		testr.check(c, rf == yf,
			"exp(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, y, std.flt64bits(rf))
	;;
}

const exp03 = {c
	/*
	   Tang's algorithm has an error of up to 0.77 ulps. This
	   is not terrible (musl appears to follow it, for example).
	   Here we quarantine off some known-bad results.
	 */

	var inputs : (uint32, uint32, uint32)[:] = [
		(0x42020000, 0x56eccf79, 0x56eccf78),
		(0x3ec40600, 0x3fbbb54b, 0x3fbbb54c),
	][:]

	for (x, y_perfect, y_acceptable) : inputs
		var xf : flt32 = std.flt32frombits(x)
		var ypf : flt32 = std.flt32frombits(y_perfect)
		var yaf : flt32 = std.flt32frombits(y_acceptable)
		var rf = math.exp(xf)
		if rf != ypf && rf != yaf
		testr.fail(c, "exp(0x{b=16,w=8,p=0}) was 0x{b=16,w=8,p=0}. It should have been 0x{b=16,w=8,p=0}, although we will also accept 0x{b=16,w=8,p=0}",
			x, std.flt32bits(rf), y_perfect, y_acceptable)
		;;
	;;
}

const exp04 = {c
	/*
	   Tang's algorithm has an error of up to 0.77 ulps. This
	   is not terrible (musl appears to follow it, for example).
	   Here we quarantine off some known-bad results.
	 */

	var inputs : (uint64, uint64, uint64)[:] = [
		(0x3cda000000000000, 0x3ff0000000000006, 0x3ff0000000000007),
		(0x3d57020000000000, 0x3ff00000000005c0, 0x3ff00000000005c1),
		(0x3d58020000000000, 0x3ff0000000000600, 0x3ff0000000000601),
		(0xc087030000000000, 0x0000000000000c6d, 0x0000000000000c6e),
		(0xc011070000000000, 0x3f8d039e34c59187, 0x3f8d039e34c59186),
		(0xbd50070000000000, 0x3feffffffffff7fc, 0x3feffffffffff7fd),
		(0xbd430e0000000000, 0x3feffffffffffb3c, 0x3feffffffffffb3d),
	][:]

	for (x, y_perfect, y_acceptable) : inputs
		var xf : flt64 = std.flt64frombits(x)
		var ypf : flt64 = std.flt64frombits(y_perfect)
		var yaf : flt64 = std.flt64frombits(y_acceptable)
		var rf = math.exp(xf)
		if rf != ypf && rf != yaf
		testr.fail(c, "exp(0x{b=16,w=16,p=0}) was 0x{b=16,w=16,p=0}. It should have been 0x{b=16,w=16,p=0}, although we will also accept 0x{b=16,w=16,p=0}",
			x, std.flt64bits(rf), y_perfect, y_acceptable)
		;;
	;;
}

const expm101 = {c
	var inputs : (uint32, uint32)[:] = [
		(0x00000000, 0x00000000),
		(0x80000000, 0x80000000),
		(0x3f000000, 0x3f261299),
		(0x3c000000, 0x3c008056),
		(0x42000000, 0x568fa1fe),
		(0xc2b00000, 0xbf800000),
		(0xc2b20000, 0xbf800000),
		(0x01000000, 0x01000000),
		(0x40000000, 0x40cc7326),
		(0x42b17200, 0x7f7ff404),
		(0x415a3cf2, 0x494cd0e3),
		(0x7f800000, 0x7f800000),
		(0xff800000, 0xbf800000),
		(0x7a2028b1, 0x7f800000),
		(0xa201a23a, 0xa201a23a),
		(0xc0000000, 0xbf5d5aab),
		(0xbe934b10, 0xbe7fffff),
		(0xbe934b11, 0xbe800000),
		(0xbe934b12, 0xbe800001),
		(0x3e647fbe, 0x3e800000),
		(0x3e647fbf, 0x3e800000),
		(0x3e647fc0, 0x3e800001),
		(0xc0f744f5, 0xbf7fe31e),
		(0x4210297a, 0x597f31f5), /* J = 0 */
		(0x3f34c3cd, 0x3f83573d), /* J = 1 */
		(0x3f3a52b6, 0x3f89087b), /* J = 2 */
		(0xbf20e72b, 0xbeeee940), /*  ...  */
		(0x41f4bd2a, 0x558c999f),
		(0xc02a0418, 0xbf6e07cd),
		(0xc0293a2a, 0xbf6dcec1),
		(0x40b62779, 0x4393ca4b),
		(0x3fc680ac, 0x406dc6a4),
		(0x3fc9d2c6, 0x4075b516),
		(0xbfedd645, 0xbf581273),
		(0x3e70e5d1, 0x3e87cbdb),
		(0xbeddcacc, 0xbeb3ffd9),
		(0x3e8beb21, 0x3ea0e776),
		(0x3e9ded31, 0x3eb8fe1f),
		(0x40e8503c, 0x44b19ed8),
		(0x40d265cb, 0x4432f91f),
		(0xbea0f9bc, 0xbe8a2036),
		(0x3ec42672, 0x3eef04c4),
		(0xc140e8cc, 0xbf7fff9f),
		(0x4117320e, 0x46467e73),
		(0x3ee8b75d, 0x3f134ef0),
		(0xc03f51f1, 0xbf731e4e),
		(0x42733615, 0x6b52d3d4),
		(0x3f02f2b5, 0x3f2af617),
		(0xbf5ac925, 0xbf131660),
		(0x40813277, 0x425eb7ac),
		(0x41842e94, 0x4b64b1dd),
		(0x41b0ba81, 0x4f6a0cc1),
		(0xc061d7c2, 0xbf787d28),
		(0xc0611682, 0xbf786657),
		(0x40dcd7e9, 0x447827c5), /* J = 31 */
	][:]

	for (x, y) : inputs
		var xf : flt32 = std.flt32frombits(x)
		var yf : flt32 = std.flt32frombits(y)
		var rf = math.expm1(xf)
		testr.check(c, rf == yf,
			"expm1(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, y, std.flt32bits(rf))
	;;
}

const expm102 = {c
	var inputs : (uint64, uint64)[:] = [
		(0x0000000000000000, 0x0000000000000000),
		(0x404ef04831cb65ed, 0x45834ac37c44b3d3),
		(0x7ff0000000000000, 0x7ff0000000000000),
		(0xfff0000000000000, 0xbff0000000000000),
		(0x80318a89f290021a, 0x80318a89f290021a),
		(0xc0180881a9e73af6, 0xbfefebdcaf24d5fe),
		(0xc020cedaedb028c9, 0xbfeffe2a4ee5ba79),
		(0xbfe62812ff80cb9e, 0xbfdff9cf6758cc6a), /* J = 0 */
		(0xbfe526dab7e5054c, 0xbfdef44fe4876d02), /* J = 1 */
		(0x3ff6ea5c51cbf0f2, 0x400980f836e2c055), /* J = 2 */
		(0x403f4315360b2cdc, 0x42c12ad5f692ffff), /*  ...  */
		(0x3fe93f778a9dc013, 0x3ff3381168aca01e),
		(0x405023f373e01862, 0x45c1aa771de3ba9c),
		(0xbfff56366f3b92de, 0xbfeb7c693f8bdbb8),
		(0xc0159bcd07244a34, 0xbfefdb1461286124),
		(0x40079bbc23a67f90, 0x40322039bbbb5e2e),
		(0xbffe1933d2c0ed70, 0xbfeb1f6c166582bb),
		(0xc009ea7d09d84479, 0xbfeebf01fa92741c),
		(0x405d84f7563a2612, 0x4a946476fb27817e),
		(0x4045f770a45f8e7f, 0x43e4da111dae0dfb),
		(0x4070e9a83b352180, 0x585516d4e37bd9f6),
		(0x3fefcdb2a528c6e8, 0x3ffb39ec926d8a50),
		(0x3fd52b5e7995f00c, 0x3fd91739183464e0),
		(0xbfd625845bbaf98f, 0xbfd2b893d222b8f2),
		(0xbfd43c0407d114d5, 0xbfd15909a4bea38e),
		(0x3fd93f8288681821, 0x3fdef406a9f7c4b1),
		(0x3fdaad696fbfea76, 0x3fe08c8035acbd0b),
		(0x405e9b6f4b4bc7f3, 0x4af8b6ad079946a7),
		(0x3fdc85cf6b85bfaf, 0x3fe1f811193e5cf5),
		(0xbfed55f9b317d7eb, 0xbfe334b0378703a0),
		(0x406ee7f396a46c9b, 0x563a11333c75a10f),
		(0x4031266dc880810e, 0x417ac458c1525e64),
		(0xc019905c018b6d96, 0xbfeff243dffe774d),
		(0x404dc17e83d7ee6b, 0x454cfbf6572d627f),
		(0xc013dcd6fae06405, 0xbfefc6dfe34e5408),
		(0x402762d99fa5cfda, 0x40fd3b9a2004f68b),
		(0xbfe89074f132e353, 0xbfe12602fb3c9806),
		(0x4077c7ea24627ae7, 0x623ea61f88281bd5),
		(0xbff6a873237d8072, 0xbfe83c311800b6ee), /* J = 31 */
	][:]

	for (x, y) : inputs
		var xf : flt64 = std.flt64frombits(x)
		var yf : flt64 = std.flt64frombits(y)
		var rf = math.expm1(xf)
		testr.check(c, rf == yf,
			"expm1(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, y, std.flt64bits(rf))
	;;
}

const expm103 = {c
	/*
	   As with exp, there is some accepted error in expm1.
	 */

	var inputs : (uint32, uint32, uint32)[:] = [
		(0x34000000, 0x34000001, 0x34000000),
		(0xbe651dea, 0xbe4d4b4d, 0xbe4d4b4c),
	][:]

	for (x, y_perfect, y_acceptable) : inputs
		var xf : flt32 = std.flt32frombits(x)
		var ypf : flt32 = std.flt32frombits(y_perfect)
		var yaf : flt32 = std.flt32frombits(y_acceptable)
		var rf = math.expm1(xf)
		if rf != ypf && rf != yaf
		testr.fail(c, "expm1(0x{b=16,w=8,p=0}) was 0x{b=16,w=8,p=0}. It should have been 0x{b=16,w=8,p=0}, although we will also accept 0x{b=16,w=8,p=0}",
			x, std.flt32bits(rf), y_perfect, y_acceptable)
		;;
	;;
}

const expm104 = {c
	/*
	   As with exp, there is some accepted error in expm1.
	 */

	var inputs : (uint64, uint64, uint64)[:] = [
		(0xbf9d0b5aadc4d0ac, 0xbf9ca2e5b7bfa859, 0xbf9ca2e5b7bfa85a),
		(0x3fc2dbb101fe0392, 0x3fc451731cc0e358, 0x3fc451731cc0e359),
		(0x3fc8a39bc9c32fec, 0x3fcb2b988c3e0b2f, 0x3fcb2b988c3e0b30),
	][:]

	for (x, y_perfect, y_acceptable) : inputs
		var xf : flt64 = std.flt64frombits(x)
		var ypf : flt64 = std.flt64frombits(y_perfect)
		var yaf : flt64 = std.flt64frombits(y_acceptable)
		var rf = math.expm1(xf)
		if rf != ypf && rf != yaf
		testr.fail(c, "expm1(0x{b=16,w=16,p=0}) was 0x{b=16,w=16,p=0}. It should have been 0x{b=16,w=16,p=0}, although we will also accept 0x{b=16,w=16,p=0}",
			x, std.flt64bits(rf), y_perfect, y_acceptable)
		;;
	;;
}