1175463Sdas/*- 2175463Sdas * Copyright (c) 2008 David Schultz <das@FreeBSD.org> 3175463Sdas * All rights reserved. 4175463Sdas * 5175463Sdas * Redistribution and use in source and binary forms, with or without 6175463Sdas * modification, are permitted provided that the following conditions 7175463Sdas * are met: 8175463Sdas * 1. Redistributions of source code must retain the above copyright 9175463Sdas * notice, this list of conditions and the following disclaimer. 10175463Sdas * 2. Redistributions in binary form must reproduce the above copyright 11175463Sdas * notice, this list of conditions and the following disclaimer in the 12175463Sdas * documentation and/or other materials provided with the distribution. 13175463Sdas * 14175463Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15175463Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16175463Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17175463Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18175463Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19175463Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20175463Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21175463Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22175463Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23175463Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24175463Sdas * SUCH DAMAGE. 25175463Sdas */ 26175463Sdas 27175463Sdas/* 28175463Sdas * Tests for corner cases in exp*(). 29175463Sdas */ 30175463Sdas 31175463Sdas#include <sys/cdefs.h> 32175463Sdas__FBSDID("$FreeBSD$"); 33175463Sdas 34175463Sdas#include <assert.h> 35175463Sdas#include <fenv.h> 36175463Sdas#include <float.h> 37175463Sdas#include <math.h> 38175463Sdas#include <stdio.h> 39175463Sdas 40175463Sdas#ifdef __i386__ 41175463Sdas#include <ieeefp.h> 42175463Sdas#endif 43175463Sdas 44175463Sdas#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ 45175463Sdas FE_OVERFLOW | FE_UNDERFLOW) 46175463Sdas 47175463Sdas#pragma STDC FENV_ACCESS ON 48175463Sdas 49175463Sdas/* 50175463Sdas * Test that a function returns the correct value and sets the 51175463Sdas * exception flags correctly. The exceptmask specifies which 52175463Sdas * exceptions we should check. We need to be lenient for several 53175463Sdas * reasoons, but mainly because on some architectures it's impossible 54175463Sdas * to raise FE_OVERFLOW without raising FE_INEXACT. 55175463Sdas * 56175463Sdas * These are macros instead of functions so that assert provides more 57175463Sdas * meaningful error messages. 58175463Sdas * 59175463Sdas * XXX The volatile here is to avoid gcc's bogus constant folding and work 60175463Sdas * around the lack of support for the FENV_ACCESS pragma. 61175463Sdas */ 62175463Sdas#define test(func, x, result, exceptmask, excepts) do { \ 63175463Sdas volatile long double _d = x; \ 64175463Sdas assert(feclearexcept(FE_ALL_EXCEPT) == 0); \ 65175463Sdas assert(fpequal((func)(_d), (result))); \ 66175463Sdas assert(((func), fetestexcept(exceptmask) == (excepts))); \ 67175463Sdas} while (0) 68175463Sdas 69175463Sdas/* Test all the functions that compute b^x. */ 70175463Sdas#define testall0(x, result, exceptmask, excepts) do { \ 71175463Sdas test(exp, x, result, exceptmask, excepts); \ 72175463Sdas test(expf, x, result, exceptmask, excepts); \ 73175463Sdas test(exp2, x, result, exceptmask, excepts); \ 74175463Sdas test(exp2f, x, result, exceptmask, excepts); \ 75175463Sdas test(exp2l, x, result, exceptmask, excepts); \ 76175463Sdas} while (0) 77175463Sdas 78175463Sdas/* Test all the functions that compute b^x - 1. */ 79175463Sdas#define testall1(x, result, exceptmask, excepts) do { \ 80175463Sdas test(expm1, x, result, exceptmask, excepts); \ 81175463Sdas test(expm1f, x, result, exceptmask, excepts); \ 82175463Sdas} while (0) 83175463Sdas 84175463Sdas/* 85175463Sdas * Determine whether x and y are equal, with two special rules: 86175463Sdas * +0.0 != -0.0 87175463Sdas * NaN == NaN 88175463Sdas */ 89175463Sdasint 90175463Sdasfpequal(long double x, long double y) 91175463Sdas{ 92216222Sdas return ((x == y && !signbit(x) == !signbit(y)) || isnan(x) && isnan(y)); 93175463Sdas} 94175463Sdas 95175463Sdasvoid 96175463Sdasrun_generic_tests(void) 97175463Sdas{ 98175463Sdas 99175463Sdas /* exp(0) == 1, no exceptions raised */ 100175463Sdas testall0(0.0, 1.0, ALL_STD_EXCEPT, 0); 101175463Sdas testall1(0.0, 0.0, ALL_STD_EXCEPT, 0); 102175463Sdas testall0(-0.0, 1.0, ALL_STD_EXCEPT, 0); 103175463Sdas testall1(-0.0, -0.0, ALL_STD_EXCEPT, 0); 104175463Sdas 105175463Sdas /* exp(NaN) == NaN, no exceptions raised */ 106175463Sdas testall0(NAN, NAN, ALL_STD_EXCEPT, 0); 107175463Sdas testall1(NAN, NAN, ALL_STD_EXCEPT, 0); 108175463Sdas 109175463Sdas /* exp(Inf) == Inf, no exceptions raised */ 110175463Sdas testall0(INFINITY, INFINITY, ALL_STD_EXCEPT, 0); 111175463Sdas testall1(INFINITY, INFINITY, ALL_STD_EXCEPT, 0); 112175463Sdas 113175463Sdas /* exp(-Inf) == 0, no exceptions raised */ 114175463Sdas testall0(-INFINITY, 0.0, ALL_STD_EXCEPT, 0); 115175463Sdas testall1(-INFINITY, -1.0, ALL_STD_EXCEPT, 0); 116175463Sdas 117175463Sdas /* exp(big) == Inf, overflow exception */ 118175463Sdas testall0(50000.0, INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_OVERFLOW); 119175463Sdas testall1(50000.0, INFINITY, ALL_STD_EXCEPT & ~FE_INEXACT, FE_OVERFLOW); 120175463Sdas 121175463Sdas /* exp(small) == 0, underflow and inexact exceptions */ 122175463Sdas testall0(-50000.0, 0.0, ALL_STD_EXCEPT, FE_UNDERFLOW | FE_INEXACT); 123175467Sdas testall1(-50000.0, -1.0, ALL_STD_EXCEPT, FE_INEXACT); 124175463Sdas} 125175463Sdas 126175463Sdasvoid 127175463Sdasrun_exp2_tests(void) 128175463Sdas{ 129175463Sdas int i; 130175463Sdas 131175463Sdas /* 132175463Sdas * We should insist that exp2() return exactly the correct 133175463Sdas * result and not raise an inexact exception for integer 134175463Sdas * arguments. 135175463Sdas */ 136175463Sdas feclearexcept(FE_ALL_EXCEPT); 137175463Sdas for (i = FLT_MIN_EXP - FLT_MANT_DIG; i < FLT_MAX_EXP; i++) { 138175463Sdas assert(exp2f(i) == ldexpf(1.0, i)); 139175463Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 0); 140175463Sdas } 141175463Sdas for (i = DBL_MIN_EXP - DBL_MANT_DIG; i < DBL_MAX_EXP; i++) { 142175463Sdas assert(exp2(i) == ldexp(1.0, i)); 143175463Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 0); 144175463Sdas } 145175463Sdas for (i = LDBL_MIN_EXP - LDBL_MANT_DIG; i < LDBL_MAX_EXP; i++) { 146175463Sdas assert(exp2l(i) == ldexpl(1.0, i)); 147175463Sdas assert(fetestexcept(ALL_STD_EXCEPT) == 0); 148175463Sdas } 149175463Sdas} 150175463Sdas 151175463Sdasint 152175463Sdasmain(int argc, char *argv[]) 153175463Sdas{ 154175463Sdas 155176375Sdas printf("1..3\n"); 156175463Sdas 157175463Sdas run_generic_tests(); 158175463Sdas printf("ok 1 - exponential\n"); 159175463Sdas 160175463Sdas#ifdef __i386__ 161175463Sdas fpsetprec(FP_PE); 162175463Sdas run_generic_tests(); 163175463Sdas#endif 164175463Sdas printf("ok 2 - exponential\n"); 165175463Sdas 166175463Sdas run_exp2_tests(); 167175463Sdas printf("ok 3 - exponential\n"); 168175463Sdas 169175463Sdas return (0); 170175463Sdas} 171