1180237Sdas/*- 2180237Sdas * Copyright (c) 2008 David Schultz <das@FreeBSD.org> 3180237Sdas * All rights reserved. 4180237Sdas * 5180237Sdas * Redistribution and use in source and binary forms, with or without 6180237Sdas * modification, are permitted provided that the following conditions 7180237Sdas * are met: 8180237Sdas * 1. Redistributions of source code must retain the above copyright 9180237Sdas * notice, this list of conditions and the following disclaimer. 10180237Sdas * 2. Redistributions in binary form must reproduce the above copyright 11180237Sdas * notice, this list of conditions and the following disclaimer in the 12180237Sdas * documentation and/or other materials provided with the distribution. 13180237Sdas * 14180237Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15180237Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16180237Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17180237Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18180237Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19180237Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20180237Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21180237Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22180237Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23180237Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24180237Sdas * SUCH DAMAGE. 25180237Sdas */ 26180237Sdas 27180237Sdas/* 28180237Sdas * Tests for fmax{,f,l}() and fmin{,f,l}. 29180237Sdas */ 30180237Sdas 31180237Sdas#include <sys/cdefs.h> 32180237Sdas__FBSDID("$FreeBSD$"); 33180237Sdas 34180237Sdas#include <fenv.h> 35180237Sdas#include <float.h> 36180237Sdas#include <math.h> 37180237Sdas#include <stdio.h> 38180237Sdas 39180237Sdas#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ 40180237Sdas FE_OVERFLOW | FE_UNDERFLOW) 41180237Sdas 42180237Sdas#pragma STDC FENV_ACCESS ON 43180237Sdas 44180237Sdas/* 45180237Sdas * Test for equality with two special rules: 46180237Sdas * fpequal(NaN, NaN) is true 47180237Sdas * fpequal(+0.0, -0.0) is false 48180237Sdas */ 49216221Sdasstatic inline int 50180237Sdasfpequal(long double x, long double y) 51180237Sdas{ 52180237Sdas 53216222Sdas return ((x == y && !signbit(x) == !signbit(y)) 54216222Sdas || (isnan(x) && isnan(y))); 55180237Sdas} 56180237Sdas 57180237Sdas/* 58180237Sdas * Test whether func(x, y) has the expected result, and make sure no 59180237Sdas * exceptions are raised. 60180237Sdas */ 61180237Sdas#define TEST(func, type, x, y, expected) do { \ 62180237Sdas type __x = (x); /* convert before we clear exceptions */ \ 63180237Sdas type __y = (y); \ 64180237Sdas feclearexcept(ALL_STD_EXCEPT); \ 65180237Sdas long double __result = func((__x), (__y)); \ 66180237Sdas if (fetestexcept(ALL_STD_EXCEPT)) { \ 67216221Sdas fprintf(stderr, #func "(%.20Lg, %.20Lg) raised 0x%x\n", \ 68180237Sdas (x), (y), fetestexcept(FE_ALL_EXCEPT)); \ 69180237Sdas ok = 0; \ 70180237Sdas } \ 71180237Sdas if (!fpequal(__result, (expected))) { \ 72180237Sdas fprintf(stderr, #func "(%.20Lg, %.20Lg) = %.20Lg, " \ 73180237Sdas "expected %.20Lg\n", (x), (y), __result, (expected)); \ 74180237Sdas ok = 0; \ 75180237Sdas } \ 76180237Sdas} while (0) 77180237Sdas 78180237Sdasint 79180237Sdastestall_r(long double big, long double small) 80180237Sdas{ 81180237Sdas int ok; 82180237Sdas 83180237Sdas long double expected_max = isnan(big) ? small : big; 84180237Sdas long double expected_min = isnan(small) ? big : small; 85180237Sdas ok = 1; 86180237Sdas 87180237Sdas TEST(fmaxf, float, big, small, expected_max); 88180237Sdas TEST(fmaxf, float, small, big, expected_max); 89180237Sdas TEST(fmax, double, big, small, expected_max); 90180237Sdas TEST(fmax, double, small, big, expected_max); 91180237Sdas TEST(fmaxl, long double, big, small, expected_max); 92180237Sdas TEST(fmaxl, long double, small, big, expected_max); 93180237Sdas TEST(fminf, float, big, small, expected_min); 94180237Sdas TEST(fminf, float, small, big, expected_min); 95180237Sdas TEST(fmin, double, big, small, expected_min); 96180237Sdas TEST(fmin, double, small, big, expected_min); 97180237Sdas TEST(fminl, long double, big, small, expected_min); 98180237Sdas TEST(fminl, long double, small, big, expected_min); 99180237Sdas 100180237Sdas return (ok); 101180237Sdas} 102180237Sdas 103180237Sdas/* 104180237Sdas * Test all the functions: fmaxf, fmax, fmaxl, fminf, fmin, and fminl, 105180237Sdas * in all rounding modes and with the arguments in different orders. 106180237Sdas * The input 'big' must be >= 'small'. 107180237Sdas */ 108216221Sdasvoid 109180237Sdastestall(int testnum, long double big, long double small) 110180237Sdas{ 111180237Sdas static const int rmodes[] = { 112180237Sdas FE_TONEAREST, FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO 113180237Sdas }; 114180237Sdas int i; 115180237Sdas 116180237Sdas for (i = 0; i < 4; i++) { 117180237Sdas fesetround(rmodes[i]); 118180237Sdas if (!testall_r(big, small)) { 119180237Sdas fprintf(stderr, "FAILURE in rounding mode %d\n", 120180237Sdas rmodes[i]); 121180237Sdas break; 122180237Sdas } 123180237Sdas } 124180237Sdas printf("%sok %d - big = %.20Lg, small = %.20Lg\n", 125180237Sdas (i == 4) ? "" : "not ", testnum, big, small); 126180237Sdas} 127180237Sdas 128180237Sdasint 129180237Sdasmain(int argc, char *argv[]) 130180237Sdas{ 131180237Sdas 132180237Sdas printf("1..12\n"); 133180237Sdas 134180237Sdas testall(1, 1.0, 0.0); 135180237Sdas testall(2, 42.0, nextafterf(42.0, -INFINITY)); 136180237Sdas testall(3, nextafterf(42.0, INFINITY), 42.0); 137180237Sdas testall(4, -5.0, -5.0); 138180237Sdas testall(5, -3.0, -4.0); 139180237Sdas testall(6, 1.0, NAN); 140180237Sdas testall(7, INFINITY, NAN); 141180237Sdas testall(8, INFINITY, 1.0); 142180237Sdas testall(9, -3.0, -INFINITY); 143180237Sdas testall(10, 3.0, -INFINITY); 144180237Sdas testall(11, NAN, NAN); 145180237Sdas 146180237Sdas /* This test isn't strictly required to work by C99. */ 147180237Sdas testall(12, 0.0, -0.0); 148180237Sdas 149180237Sdas return (0); 150180237Sdas} 151