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