aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDavid Schultz <das@FreeBSD.org>2008-01-18 21:46:54 +0000
committerDavid Schultz <das@FreeBSD.org>2008-01-18 21:46:54 +0000
commite5af135aadfbe0d453e01a93ab53a2f784ffd16d (patch)
treef5fcd876d045b14de9605548817324f077ee1903 /tools
parent3d2cc91218f88391aca25adb8629b80caeccc33e (diff)
downloadsrc-e5af135aadfbe0d453e01a93ab53a2f784ffd16d.tar.gz
src-e5af135aadfbe0d453e01a93ab53a2f784ffd16d.zip
Add some regression tests for libm's exponential functions. These
mostly just test corner cases rather than accuracy. Some of the tests don't pass right now if you compile libm at -O2 due to gcc constant-folding some things that it shouldn't. I'll fix that shortly.
Notes
Notes: svn path=/head/; revision=175463
Diffstat (limited to 'tools')
-rw-r--r--tools/regression/lib/msun/Makefile2
-rw-r--r--tools/regression/lib/msun/test-exponential.c170
-rw-r--r--tools/regression/lib/msun/test-exponential.t10
3 files changed, 181 insertions, 1 deletions
diff --git a/tools/regression/lib/msun/Makefile b/tools/regression/lib/msun/Makefile
index 60f94d8b057e..cf5443c6d26e 100644
--- a/tools/regression/lib/msun/Makefile
+++ b/tools/regression/lib/msun/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-TESTS= test-csqrt test-fenv test-ilogb test-lrint \
+TESTS= test-csqrt test-exponential test-fenv test-ilogb test-lrint \
test-lround test-nan test-next test-rem
CFLAGS+= -O0 -lm
diff --git a/tools/regression/lib/msun/test-exponential.c b/tools/regression/lib/msun/test-exponential.c
new file mode 100644
index 000000000000..e5c2beaf0ee9
--- /dev/null
+++ b/tools/regression/lib/msun/test-exponential.c
@@ -0,0 +1,170 @@
+/*-
+ * Copyright (c) 2008 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Tests for corner cases in exp*().
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef __i386__
+#include <ieeefp.h>
+#endif
+
+#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
+ FE_OVERFLOW | FE_UNDERFLOW)
+
+#pragma STDC FENV_ACCESS ON
+
+/*
+ * Test that a function returns the correct value and sets the
+ * exception flags correctly. The exceptmask specifies which
+ * exceptions we should check. We need to be lenient for several
+ * reasoons, but mainly because on some architectures it's impossible
+ * to raise FE_OVERFLOW without raising FE_INEXACT.
+ *
+ * These are macros instead of functions so that assert provides more
+ * meaningful error messages.
+ *
+ * XXX The volatile here is to avoid gcc's bogus constant folding and work
+ * around the lack of support for the FENV_ACCESS pragma.
+ */
+#define test(func, x, result, exceptmask, excepts) do { \
+ volatile long double _d = x; \
+ assert(feclearexcept(FE_ALL_EXCEPT) == 0); \
+ assert(fpequal((func)(_d), (result))); \
+ assert(((func), fetestexcept(exceptmask) == (excepts))); \
+} while (0)
+
+/* Test all the functions that compute b^x. */
+#define testall0(x, result, exceptmask, excepts) do { \
+ test(exp, x, result, exceptmask, excepts); \
+ test(expf, x, result, exceptmask, excepts); \
+ test(exp2, x, result, exceptmask, excepts); \
+ test(exp2f, x, result, exceptmask, excepts); \
+ test(exp2l, x, result, exceptmask, excepts); \
+} while (0)
+
+/* Test all the functions that compute b^x - 1. */
+#define testall1(x, result, exceptmask, excepts) do { \
+ test(expm1, x, result, exceptmask, excepts); \
+ test(expm1f, x, result, exceptmask, excepts); \
+} while (0)
+
+/*
+ * Determine whether x and y are equal, with two special rules:
+ * +0.0 != -0.0
+ * NaN == NaN
+ */
+int
+fpequal(long double x, long double y)
+{
+ return ((x == y && signbit(x) == signbit(y)) || isnan(x) && isnan(y));
+}
+
+void
+run_generic_tests(void)
+{
+
+ /* exp(0) == 1, no exceptions raised */
+ testall0(0.0, 1.0, ALL_STD_EXCEPT, 0);
+ testall1(0.0, 0.0, ALL_STD_EXCEPT, 0);
+ testall0(-0.0, 1.0, ALL_STD_EXCEPT, 0);
+ testall1(-0.0, -0.0, ALL_STD_EXCEPT, 0);
+
+ /* exp(NaN) == NaN, no exceptions raised */
+ testall0(NAN, NAN, ALL_STD_EXCEPT, 0);
+ testall1(NAN, NAN, ALL_STD_EXCEPT, 0);
+
+ /* exp(Inf) == Inf, no exceptions raised */
+ testall0(INFINITY, INFINITY, ALL_STD_EXCEPT, 0);
+ testall1(INFINITY, INFINITY, ALL_STD_EXCEPT, 0);
+
+ /* exp(-Inf) == 0, no exceptions raised */
+ testall0(-INFINITY, 0.0, ALL_STD_EXCEPT, 0);
+ testall1(-INFINITY, -1.0, ALL_STD_EXCEPT, 0);
+
+ /* exp(big) == Inf, overflow exception */
+ testall0(50000.0, INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_OVERFLOW);
+ testall1(50000.0, INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_OVERFLOW);
+
+ /* exp(small) == 0, underflow and inexact exceptions */
+ testall0(-50000.0, 0.0, ALL_STD_EXCEPT, FE_UNDERFLOW | FE_INEXACT);
+ testall1(-50000.0, -1.0, ALL_STD_EXCEPT, FE_UNDERFLOW | FE_INEXACT);
+}
+
+void
+run_exp2_tests(void)
+{
+ int i;
+
+ /*
+ * We should insist that exp2() return exactly the correct
+ * result and not raise an inexact exception for integer
+ * arguments.
+ */
+ feclearexcept(FE_ALL_EXCEPT);
+ for (i = FLT_MIN_EXP - FLT_MANT_DIG; i < FLT_MAX_EXP; i++) {
+ assert(exp2f(i) == ldexpf(1.0, i));
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+ }
+ for (i = DBL_MIN_EXP - DBL_MANT_DIG; i < DBL_MAX_EXP; i++) {
+ assert(exp2(i) == ldexp(1.0, i));
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+ }
+ for (i = LDBL_MIN_EXP - LDBL_MANT_DIG; i < LDBL_MAX_EXP; i++) {
+ assert(exp2l(i) == ldexpl(1.0, i));
+ assert(fetestexcept(ALL_STD_EXCEPT) == 0);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..2\n");
+
+ run_generic_tests();
+ printf("ok 1 - exponential\n");
+
+#ifdef __i386__
+ fpsetprec(FP_PE);
+ run_generic_tests();
+#endif
+ printf("ok 2 - exponential\n");
+
+ run_exp2_tests();
+ printf("ok 3 - exponential\n");
+
+ return (0);
+}
diff --git a/tools/regression/lib/msun/test-exponential.t b/tools/regression/lib/msun/test-exponential.t
new file mode 100644
index 000000000000..8bdfd03be81b
--- /dev/null
+++ b/tools/regression/lib/msun/test-exponential.t
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $FreeBSD$
+
+cd `dirname $0`
+
+executable=`basename $0 .t`
+
+make $executable 2>&1 > /dev/null
+
+exec ./$executable