1251241Sdas/*- 2251241Sdas * Copyright (c) 2005-2013 David Schultz <das@FreeBSD.org> 3251241Sdas * All rights reserved. 4251241Sdas * 5251241Sdas * Redistribution and use in source and binary forms, with or without 6251241Sdas * modification, are permitted provided that the following conditions 7251241Sdas * are met: 8251241Sdas * 1. Redistributions of source code must retain the above copyright 9251241Sdas * notice, this list of conditions and the following disclaimer. 10251241Sdas * 2. Redistributions in binary form must reproduce the above copyright 11251241Sdas * notice, this list of conditions and the following disclaimer in the 12251241Sdas * documentation and/or other materials provided with the distribution. 13251241Sdas * 14251241Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15251241Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16251241Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17251241Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18251241Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19251241Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20251241Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21251241Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22251241Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23251241Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24251241Sdas * SUCH DAMAGE. 25251241Sdas * 26251241Sdas * $FreeBSD$ 27251241Sdas */ 28251241Sdas 29251241Sdas#ifndef _TEST_UTILS_H_ 30251241Sdas#define _TEST_UTILS_H_ 31251241Sdas 32251241Sdas#include <complex.h> 33251241Sdas#include <fenv.h> 34251241Sdas 35251241Sdas/* 36251241Sdas * Implementations are permitted to define additional exception flags 37251241Sdas * not specified in the standard, so it is not necessarily true that 38251241Sdas * FE_ALL_EXCEPT == ALL_STD_EXCEPT. 39251241Sdas */ 40251241Sdas#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ 41251241Sdas FE_OVERFLOW | FE_UNDERFLOW) 42251241Sdas#define OPT_INVALID (ALL_STD_EXCEPT & ~FE_INVALID) 43251241Sdas#define OPT_INEXACT (ALL_STD_EXCEPT & ~FE_INEXACT) 44251241Sdas#define FLT_ULP() ldexpl(1.0, 1 - FLT_MANT_DIG) 45251241Sdas#define DBL_ULP() ldexpl(1.0, 1 - DBL_MANT_DIG) 46251241Sdas#define LDBL_ULP() ldexpl(1.0, 1 - LDBL_MANT_DIG) 47251241Sdas 48251241Sdas/* 49251241Sdas * Flags that control the behavior of various fpequal* functions. 50251241Sdas * XXX This is messy due to merging various notions of "close enough" 51251241Sdas * that are best suited for different functions. 52251241Sdas * 53251241Sdas * CS_REAL 54251241Sdas * CS_IMAG 55251241Sdas * CS_BOTH 56251241Sdas * (cfpequal_cs, fpequal_tol, cfpequal_tol) Whether to check the sign of 57251241Sdas * the real part of the result, the imaginary part, or both. 58251241Sdas * 59251241Sdas * FPE_ABS_ZERO 60251241Sdas * (fpequal_tol, cfpequal_tol) If set, treats the tolerance as an absolute 61251241Sdas * tolerance when the expected value is 0. This is useful when there is 62251241Sdas * round-off error in the input, e.g., cos(Pi/2) ~= 0. 63251241Sdas */ 64251241Sdas#define CS_REAL 0x01 65251241Sdas#define CS_IMAG 0x02 66251241Sdas#define CS_BOTH (CS_REAL | CS_IMAG) 67251241Sdas#define FPE_ABS_ZERO 0x04 68251241Sdas 69251241Sdas#ifdef DEBUG 70251241Sdas#define debug(...) printf(__VA_ARGS__) 71251241Sdas#else 72251241Sdas#define debug(...) (void)0 73251241Sdas#endif 74251241Sdas 75251241Sdas/* 76251241Sdas * XXX The ancient version of gcc in the base system doesn't support CMPLXL, 77251241Sdas * but we can fake it most of the time. 78251241Sdas */ 79251241Sdas#ifndef CMPLXL 80251241Sdasstatic inline long double complex 81251241SdasCMPLXL(long double x, long double y) 82251241Sdas{ 83251241Sdas long double complex z; 84251241Sdas 85251241Sdas __real__ z = x; 86251241Sdas __imag__ z = y; 87251241Sdas return (z); 88251241Sdas} 89251241Sdas#endif 90251241Sdas 91251241Sdas/* 92251241Sdas * Compare d1 and d2 using special rules: NaN == NaN and +0 != -0. 93251241Sdas * Fail an assertion if they differ. 94251241Sdas */ 95251241Sdasstatic int 96251241Sdasfpequal(long double d1, long double d2) 97251241Sdas{ 98251241Sdas 99251241Sdas if (d1 != d2) 100251241Sdas return (isnan(d1) && isnan(d2)); 101251241Sdas return (copysignl(1.0, d1) == copysignl(1.0, d2)); 102251241Sdas} 103251241Sdas 104251241Sdas/* 105251241Sdas * Determine whether x and y are equal, with two special rules: 106251241Sdas * +0.0 != -0.0 107251241Sdas * NaN == NaN 108251241Sdas * If checksign is 0, we compare the absolute values instead. 109251241Sdas */ 110251241Sdasstatic int 111251241Sdasfpequal_cs(long double x, long double y, int checksign) 112251241Sdas{ 113251241Sdas if (isnan(x) && isnan(y)) 114251241Sdas return (1); 115251241Sdas if (checksign) 116251241Sdas return (x == y && !signbit(x) == !signbit(y)); 117251241Sdas else 118251241Sdas return (fabsl(x) == fabsl(y)); 119251241Sdas} 120251241Sdas 121251241Sdasstatic int 122251241Sdasfpequal_tol(long double x, long double y, long double tol, unsigned int flags) 123251241Sdas{ 124251241Sdas fenv_t env; 125251241Sdas int ret; 126251241Sdas 127251241Sdas if (isnan(x) && isnan(y)) 128251241Sdas return (1); 129251241Sdas if (!signbit(x) != !signbit(y) && (flags & CS_BOTH)) 130251241Sdas return (0); 131251241Sdas if (x == y) 132251241Sdas return (1); 133251241Sdas if (tol == 0) 134251241Sdas return (0); 135251241Sdas 136251241Sdas /* Hard case: need to check the tolerance. */ 137251241Sdas feholdexcept(&env); 138251241Sdas /* 139251241Sdas * For our purposes here, if y=0, we interpret tol as an absolute 140251241Sdas * tolerance. This is to account for roundoff in the input, e.g., 141251241Sdas * cos(Pi/2) ~= 0. 142251241Sdas */ 143251241Sdas if ((flags & FPE_ABS_ZERO) && y == 0.0) 144251241Sdas ret = fabsl(x - y) <= fabsl(tol); 145251241Sdas else 146251241Sdas ret = fabsl(x - y) <= fabsl(y * tol); 147251241Sdas fesetenv(&env); 148251241Sdas return (ret); 149251241Sdas} 150251241Sdas 151251241Sdasstatic int 152251241Sdascfpequal(long double complex d1, long double complex d2) 153251241Sdas{ 154251241Sdas 155251241Sdas return (fpequal(creall(d1), creall(d2)) && 156251241Sdas fpequal(cimagl(d1), cimagl(d2))); 157251241Sdas} 158251241Sdas 159251241Sdasstatic int 160251241Sdascfpequal_cs(long double complex x, long double complex y, int checksign) 161251241Sdas{ 162251241Sdas return (fpequal_cs(creal(x), creal(y), checksign) 163251241Sdas && fpequal_cs(cimag(x), cimag(y), checksign)); 164251241Sdas} 165251241Sdas 166251241Sdasstatic int 167251241Sdascfpequal_tol(long double complex x, long double complex y, long double tol, 168251241Sdas unsigned int flags) 169251241Sdas{ 170251241Sdas return (fpequal_tol(creal(x), creal(y), tol, flags) 171251241Sdas && fpequal_tol(cimag(x), cimag(y), tol, flags)); 172251241Sdas} 173251241Sdas 174251241Sdas#endif /* _TEST_UTILS_H_ */ 175