test-exponential.c revision 225736
161033Sdfr/*-
261033Sdfr * Copyright (c) 2008 David Schultz <das@FreeBSD.org>
361033Sdfr * All rights reserved.
461033Sdfr *
561033Sdfr * Redistribution and use in source and binary forms, with or without
661033Sdfr * modification, are permitted provided that the following conditions
761033Sdfr * are met:
861033Sdfr * 1. Redistributions of source code must retain the above copyright
961033Sdfr *    notice, this list of conditions and the following disclaimer.
1061033Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1161033Sdfr *    notice, this list of conditions and the following disclaimer in the
1261033Sdfr *    documentation and/or other materials provided with the distribution.
1361033Sdfr *
1461033Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1561033Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1661033Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1761033Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1861033Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1961033Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2061033Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2161033Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2261033Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2361033Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2461033Sdfr * SUCH DAMAGE.
2561033Sdfr */
2661033Sdfr
27116182Sobrien/*
28116182Sobrien * Tests for corner cases in exp*().
29116182Sobrien */
3061033Sdfr
3185521Sjhb#include <sys/cdefs.h>
3265822Sjhb__FBSDID("$FreeBSD: stable/9/tools/regression/lib/msun/test-exponential.c 216222 2010-12-06 00:02:49Z das $");
3385560Sjhb
3461033Sdfr#include <assert.h>
35123614Sjhb#include <fenv.h>
3685521Sjhb#include <float.h>
3761033Sdfr#include <math.h>
3885521Sjhb#include <stdio.h>
39145729Ssam
40154333Sscottl#ifdef __i386__
4185521Sjhb#include <ieeefp.h>
42119708Sken#endif
43154333Sscottl
4461033Sdfr#define	ALL_STD_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \
4569774Sphk			 FE_OVERFLOW | FE_UNDERFLOW)
46123614Sjhb
47123614Sjhb#pragma STDC FENV_ACCESS ON
4861033Sdfr
4985521Sjhb/*
5067551Sjhb * Test that a function returns the correct value and sets the
5161033Sdfr * exception flags correctly. The exceptmask specifies which
5261033Sdfr * exceptions we should check. We need to be lenient for several
5361033Sdfr * reasoons, but mainly because on some architectures it's impossible
5461033Sdfr * to raise FE_OVERFLOW without raising FE_INEXACT.
5561033Sdfr *
5661033Sdfr * These are macros instead of functions so that assert provides more
57145473Ssam * meaningful error messages.
5885521Sjhb *
59145729Ssam * XXX The volatile here is to avoid gcc's bogus constant folding and work
60154333Sscottl *     around the lack of support for the FENV_ACCESS pragma.
61154167Sscottl */
62154333Sscottl#define	test(func, x, result, exceptmask, excepts)	do {		\
6361033Sdfr	volatile long double _d = x;					\
6461033Sdfr	assert(feclearexcept(FE_ALL_EXCEPT) == 0);			\
65154333Sscottl	assert(fpequal((func)(_d), (result)));				 \
66177621Sscottl	assert(((func), fetestexcept(exceptmask) == (excepts)));	\
67177621Sscottl} while (0)
68154333Sscottl
69154167Sscottl/* Test all the functions that compute b^x. */
70154167Sscottl#define	testall0(x, result, exceptmask, excepts)	do {		\
71154167Sscottl	test(exp, x, result, exceptmask, excepts);			\
72154167Sscottl	test(expf, x, result, exceptmask, excepts);			\
73154167Sscottl	test(exp2, x, result, exceptmask, excepts);			\
74154167Sscottl	test(exp2f, x, result, exceptmask, excepts);			\
75154167Sscottl	test(exp2l, x, result, exceptmask, excepts);			\
76154167Sscottl} while (0)
77154167Sscottl
78154167Sscottl/* Test all the functions that compute b^x - 1. */
79154167Sscottl#define	testall1(x, result, exceptmask, excepts)	do {		\
80154167Sscottl	test(expm1, x, result, exceptmask, excepts);			\
81154167Sscottl	test(expm1f, x, result, exceptmask, excepts);			\
82154167Sscottl} while (0)
83154167Sscottl
84154167Sscottl/*
85154167Sscottl * Determine whether x and y are equal, with two special rules:
86154167Sscottl *	+0.0 != -0.0
8785521Sjhb *	 NaN == NaN
8885521Sjhb */
89154167Sscottlint
90154167Sscottlfpequal(long double x, long double y)
91154167Sscottl{
92154167Sscottl	return ((x == y && !signbit(x) == !signbit(y)) || isnan(x) && isnan(y));
93154167Sscottl}
94154167Sscottl
95154167Sscottlvoid
96154167Sscottlrun_generic_tests(void)
97154167Sscottl{
9885521Sjhb
9985521Sjhb	/* exp(0) == 1, no exceptions raised */
10085521Sjhb	testall0(0.0, 1.0, ALL_STD_EXCEPT, 0);
10185521Sjhb	testall1(0.0, 0.0, ALL_STD_EXCEPT, 0);
10293818Sjhb	testall0(-0.0, 1.0, ALL_STD_EXCEPT, 0);
10385521Sjhb	testall1(-0.0, -0.0, ALL_STD_EXCEPT, 0);
10485521Sjhb
10585521Sjhb	/* exp(NaN) == NaN, no exceptions raised */
10685521Sjhb	testall0(NAN, NAN, ALL_STD_EXCEPT, 0);
10785521Sjhb	testall1(NAN, NAN, ALL_STD_EXCEPT, 0);
108154167Sscottl
109154167Sscottl	/* exp(Inf) == Inf, no exceptions raised */
110145729Ssam	testall0(INFINITY, INFINITY, ALL_STD_EXCEPT, 0);
111154167Sscottl	testall1(INFINITY, INFINITY, ALL_STD_EXCEPT, 0);
11261033Sdfr
11361033Sdfr	/* exp(-Inf) == 0, no exceptions raised */
11461033Sdfr	testall0(-INFINITY, 0.0, ALL_STD_EXCEPT, 0);
11585521Sjhb	testall1(-INFINITY, -1.0, ALL_STD_EXCEPT, 0);
11661033Sdfr
11761033Sdfr	/* exp(big) == Inf, overflow exception */
11885521Sjhb	testall0(50000.0, INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_OVERFLOW);
11961033Sdfr	testall1(50000.0, INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_OVERFLOW);
12061033Sdfr
12161033Sdfr	/* exp(small) == 0, underflow and inexact exceptions */
12261033Sdfr	testall0(-50000.0, 0.0, ALL_STD_EXCEPT, FE_UNDERFLOW | FE_INEXACT);
123154167Sscottl	testall1(-50000.0, -1.0, ALL_STD_EXCEPT, FE_INEXACT);
124154333Sscottl}
125154167Sscottl
12661033Sdfrvoid
12785521Sjhbrun_exp2_tests(void)
12861033Sdfr{
12985521Sjhb	int i;
13061033Sdfr
13161033Sdfr	/*
13261033Sdfr	 * We should insist that exp2() return exactly the correct
13361033Sdfr	 * result and not raise an inexact exception for integer
134154167Sscottl	 * arguments.
135154167Sscottl	 */
136154333Sscottl	feclearexcept(FE_ALL_EXCEPT);
137154167Sscottl	for (i = FLT_MIN_EXP - FLT_MANT_DIG; i < FLT_MAX_EXP; i++) {
138154333Sscottl		assert(exp2f(i) == ldexpf(1.0, i));
139154167Sscottl		assert(fetestexcept(ALL_STD_EXCEPT) == 0);
140154167Sscottl	}
141154167Sscottl	for (i = DBL_MIN_EXP - DBL_MANT_DIG; i < DBL_MAX_EXP; i++) {
142145729Ssam		assert(exp2(i) == ldexp(1.0, i));
143145729Ssam		assert(fetestexcept(ALL_STD_EXCEPT) == 0);
144145729Ssam	}
145145729Ssam	for (i = LDBL_MIN_EXP - LDBL_MANT_DIG; i < LDBL_MAX_EXP; i++) {
146145729Ssam		assert(exp2l(i) == ldexpl(1.0, i));
147145729Ssam		assert(fetestexcept(ALL_STD_EXCEPT) == 0);
148145729Ssam	}
149154333Sscottl}
150154333Sscottl
151154333Sscottlint
152145729Ssammain(int argc, char *argv[])
153145729Ssam{
154145729Ssam
15561033Sdfr	printf("1..3\n");
15661033Sdfr
15761033Sdfr	run_generic_tests();
15885521Sjhb	printf("ok 1 - exponential\n");
15985521Sjhb
16061033Sdfr#ifdef __i386__
16185521Sjhb	fpsetprec(FP_PE);
16261033Sdfr	run_generic_tests();
163154167Sscottl#endif
164154333Sscottl	printf("ok 2 - exponential\n");
165131246Sjhb
166145729Ssam	run_exp2_tests();
16785521Sjhb	printf("ok 3 - exponential\n");
168154333Sscottl
16961033Sdfr	return (0);
17061033Sdfr}
17161033Sdfr