1143231Sdas/*- 2143231Sdas * Copyright (c) 2005 David Schultz <das@FreeBSD.org> 3143231Sdas * All rights reserved. 4143231Sdas * 5143231Sdas * Redistribution and use in source and binary forms, with or without 6143231Sdas * modification, are permitted provided that the following conditions 7143231Sdas * are met: 8143231Sdas * 1. Redistributions of source code must retain the above copyright 9143231Sdas * notice, this list of conditions and the following disclaimer. 10143231Sdas * 2. Redistributions in binary form must reproduce the above copyright 11143231Sdas * notice, this list of conditions and the following disclaimer in the 12143231Sdas * documentation and/or other materials provided with the distribution. 13143231Sdas * 14143231Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15143231Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16143231Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17143231Sdas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18143231Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19143231Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20143231Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21143231Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22143231Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23143231Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24143231Sdas * SUCH DAMAGE. 25143231Sdas */ 26143231Sdas 27143231Sdas/* 28143231Sdas * Test the correctness of nextafter{,f,l} and nexttoward{,f,l}. 29143231Sdas */ 30143231Sdas 31143231Sdas#include <sys/cdefs.h> 32143231Sdas__FBSDID("$FreeBSD$"); 33143231Sdas 34143231Sdas#include <fenv.h> 35143231Sdas#include <float.h> 36143231Sdas#include <math.h> 37143231Sdas#include <stdio.h> 38143231Sdas#include <stdlib.h> 39143231Sdas 40143231Sdas#ifdef __i386__ 41143231Sdas#include <ieeefp.h> 42143231Sdas#endif 43143231Sdas 44143231Sdas#define ALL_STD_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID |\ 45143231Sdas FE_OVERFLOW | FE_UNDERFLOW) 46143231Sdas#define test(exp, ans, ex) do { \ 47143231Sdas double __ans = (ans); \ 48143231Sdas feclearexcept(ALL_STD_EXCEPT); \ 49143231Sdas _testl(#exp, __LINE__, (exp), __ans, (ex)); \ 50143231Sdas} while (0) 51143231Sdas#define testf(exp, ans, ex) do { \ 52143231Sdas float __ans = (ans); \ 53143231Sdas feclearexcept(ALL_STD_EXCEPT); \ 54143231Sdas _testl(#exp, __LINE__, (exp), __ans, (ex)); \ 55143231Sdas} while (0) 56143231Sdas#define testl(exp, ans, ex) do { \ 57143231Sdas long double __ans = (ans); \ 58143231Sdas feclearexcept(ALL_STD_EXCEPT); \ 59143231Sdas _testl(#exp, __LINE__, (exp), __ans, (ex)); \ 60143231Sdas} while (0) 61143231Sdas#define testboth(arg1, arg2, ans, ex, prec) do { \ 62143231Sdas test##prec(nextafter##prec((arg1), (arg2)), (ans), (ex)); \ 63143231Sdas test##prec(nexttoward##prec((arg1), (arg2)), (ans), (ex)); \ 64143231Sdas} while (0) 65143231Sdas#define testall(arg1, arg2, ans, ex) do { \ 66143231Sdas testboth((arg1), (arg2), (ans), (ex), ); \ 67143231Sdas testboth((arg1), (arg2), (ans), (ex), f); \ 68143231Sdas testboth((arg1), (arg2), (ans), (ex), l); \ 69143231Sdas} while (0) 70143231Sdas 71143231Sdasstatic void _testl(const char *, int, long double, long double, int); 72143231Sdasstatic double idd(double); 73143231Sdasstatic float idf(float); 74143231Sdas 75143231Sdasint 76143231Sdasmain(int argc, char *argv[]) 77143231Sdas{ 78143231Sdas static const int ex_under = FE_UNDERFLOW | FE_INEXACT; /* shorthand */ 79143231Sdas static const int ex_over = FE_OVERFLOW | FE_INEXACT; 80174494Sdas long double ldbl_small, ldbl_eps, ldbl_max; 81143231Sdas 82143231Sdas printf("1..5\n"); 83143231Sdas 84143231Sdas#ifdef __i386__ 85143231Sdas fpsetprec(FP_PE); 86143231Sdas#endif 87143231Sdas /* 88143231Sdas * We can't use a compile-time constant here because gcc on 89143231Sdas * FreeBSD/i386 assumes long doubles are truncated to the 90143231Sdas * double format. 91143231Sdas */ 92174494Sdas ldbl_small = ldexpl(1.0, LDBL_MIN_EXP - LDBL_MANT_DIG); 93174494Sdas ldbl_eps = LDBL_EPSILON; 94174494Sdas ldbl_max = ldexpl(1.0 - ldbl_eps / 2, LDBL_MAX_EXP); 95143231Sdas 96143231Sdas /* 97143231Sdas * Special cases involving zeroes. 98143231Sdas */ 99143231Sdas#define ztest(prec) \ 100143231Sdas test##prec(copysign##prec(1.0, nextafter##prec(0.0, -0.0)), -1.0, 0); \ 101143231Sdas test##prec(copysign##prec(1.0, nextafter##prec(-0.0, 0.0)), 1.0, 0); \ 102143231Sdas test##prec(copysign##prec(1.0, nexttoward##prec(0.0, -0.0)), -1.0, 0);\ 103143231Sdas test##prec(copysign##prec(1.0, nexttoward##prec(-0.0, 0.0)), 1.0, 0) 104143231Sdas 105143231Sdas ztest(); 106143231Sdas ztest(f); 107143231Sdas ztest(l); 108143231Sdas#undef ztest 109143231Sdas 110143231Sdas#define stest(next, eps, prec) \ 111143231Sdas test##prec(next(-0.0, 42.0), eps, ex_under); \ 112143231Sdas test##prec(next(0.0, -42.0), -eps, ex_under); \ 113143231Sdas test##prec(next(0.0, INFINITY), eps, ex_under); \ 114143231Sdas test##prec(next(-0.0, -INFINITY), -eps, ex_under) 115143231Sdas 116143231Sdas stest(nextafter, 0x1p-1074, ); 117143231Sdas stest(nextafterf, 0x1p-149f, f); 118174494Sdas stest(nextafterl, ldbl_small, l); 119143231Sdas stest(nexttoward, 0x1p-1074, ); 120143231Sdas stest(nexttowardf, 0x1p-149f, f); 121174494Sdas stest(nexttowardl, ldbl_small, l); 122143231Sdas#undef stest 123143231Sdas 124143231Sdas printf("ok 1 - next\n"); 125143231Sdas 126143231Sdas /* 127143231Sdas * `x == y' and NaN tests 128143231Sdas */ 129143231Sdas testall(42.0, 42.0, 42.0, 0); 130143231Sdas testall(-42.0, -42.0, -42.0, 0); 131143231Sdas testall(INFINITY, INFINITY, INFINITY, 0); 132143231Sdas testall(-INFINITY, -INFINITY, -INFINITY, 0); 133143231Sdas testall(NAN, 42.0, NAN, 0); 134143231Sdas testall(42.0, NAN, NAN, 0); 135143231Sdas testall(NAN, NAN, NAN, 0); 136143231Sdas 137143231Sdas printf("ok 2 - next\n"); 138143231Sdas 139143231Sdas /* 140143231Sdas * Tests where x is an ordinary normalized number 141143231Sdas */ 142143231Sdas testboth(1.0, 2.0, 1.0 + DBL_EPSILON, 0, ); 143143231Sdas testboth(1.0, -INFINITY, 1.0 - DBL_EPSILON/2, 0, ); 144143231Sdas testboth(1.0, 2.0, 1.0 + FLT_EPSILON, 0, f); 145143231Sdas testboth(1.0, -INFINITY, 1.0 - FLT_EPSILON/2, 0, f); 146174494Sdas testboth(1.0, 2.0, 1.0 + ldbl_eps, 0, l); 147174494Sdas testboth(1.0, -INFINITY, 1.0 - ldbl_eps/2, 0, l); 148143231Sdas 149143231Sdas testboth(-1.0, 2.0, -1.0 + DBL_EPSILON/2, 0, ); 150143231Sdas testboth(-1.0, -INFINITY, -1.0 - DBL_EPSILON, 0, ); 151143231Sdas testboth(-1.0, 2.0, -1.0 + FLT_EPSILON/2, 0, f); 152143231Sdas testboth(-1.0, -INFINITY, -1.0 - FLT_EPSILON, 0, f); 153174494Sdas testboth(-1.0, 2.0, -1.0 + ldbl_eps/2, 0, l); 154174494Sdas testboth(-1.0, -INFINITY, -1.0 - ldbl_eps, 0, l); 155143231Sdas 156143231Sdas /* Cases where nextafter(...) != nexttoward(...) */ 157174494Sdas test(nexttoward(1.0, 1.0 + ldbl_eps), 1.0 + DBL_EPSILON, 0); 158174494Sdas testf(nexttowardf(1.0, 1.0 + ldbl_eps), 1.0 + FLT_EPSILON, 0); 159174494Sdas testl(nexttowardl(1.0, 1.0 + ldbl_eps), 1.0 + ldbl_eps, 0); 160143231Sdas 161143231Sdas printf("ok 3 - next\n"); 162143231Sdas 163143231Sdas /* 164143231Sdas * Tests at word boundaries, normalization boundaries, etc. 165143231Sdas */ 166143231Sdas testboth(0x1.87654ffffffffp+0, INFINITY, 0x1.87655p+0, 0, ); 167143231Sdas testboth(0x1.87655p+0, -INFINITY, 0x1.87654ffffffffp+0, 0, ); 168143231Sdas testboth(0x1.fffffffffffffp+0, INFINITY, 0x1p1, 0, ); 169143231Sdas testboth(0x1p1, -INFINITY, 0x1.fffffffffffffp+0, 0, ); 170143231Sdas testboth(0x0.fffffffffffffp-1022, INFINITY, 0x1p-1022, 0, ); 171143231Sdas testboth(0x1p-1022, -INFINITY, 0x0.fffffffffffffp-1022, ex_under, ); 172143231Sdas 173143231Sdas testboth(0x1.fffffep0f, INFINITY, 0x1p1, 0, f); 174143231Sdas testboth(0x1p1, -INFINITY, 0x1.fffffep0f, 0, f); 175143231Sdas testboth(0x0.fffffep-126f, INFINITY, 0x1p-126f, 0, f); 176143231Sdas testboth(0x1p-126f, -INFINITY, 0x0.fffffep-126f, ex_under, f); 177143231Sdas 178143231Sdas#if LDBL_MANT_DIG == 53 179143231Sdas testboth(0x1.87654ffffffffp+0L, INFINITY, 0x1.87655p+0L, 0, l); 180143231Sdas testboth(0x1.87655p+0L, -INFINITY, 0x1.87654ffffffffp+0L, 0, l); 181143231Sdas testboth(0x1.fffffffffffffp+0L, INFINITY, 0x1p1L, 0, l); 182143231Sdas testboth(0x1p1L, -INFINITY, 0x1.fffffffffffffp+0L, 0, l); 183143231Sdas testboth(0x0.fffffffffffffp-1022L, INFINITY, 0x1p-1022L, 0, l); 184143231Sdas testboth(0x1p-1022L, -INFINITY, 0x0.fffffffffffffp-1022L, ex_under, l); 185174691Sdas#elif LDBL_MANT_DIG == 64 && !defined(__i386) 186143231Sdas testboth(0x1.87654321fffffffep+0L, INFINITY, 0x1.87654322p+0L, 0, l); 187143231Sdas testboth(0x1.87654322p+0L, -INFINITY, 0x1.87654321fffffffep+0L, 0, l); 188143231Sdas testboth(0x1.fffffffffffffffep0L, INFINITY, 0x1p1L, 0, l); 189143231Sdas testboth(0x1p1L, -INFINITY, 0x1.fffffffffffffffep0L, 0, l); 190143231Sdas testboth(0x0.fffffffffffffffep-16382L, INFINITY, 0x1p-16382L, 0, l); 191143231Sdas testboth(0x1p-16382L, -INFINITY, 192143231Sdas 0x0.fffffffffffffffep-16382L, ex_under, l); 193143231Sdas#elif LDBL_MANT_DIG == 113 194143231Sdas testboth(0x1.876543210987ffffffffffffffffp+0L, INFINITY, 195143231Sdas 0x1.876543210988p+0, 0, l); 196143231Sdas testboth(0x1.876543210988p+0L, -INFINITY, 197143231Sdas 0x1.876543210987ffffffffffffffffp+0L, 0, l); 198143231Sdas testboth(0x1.ffffffffffffffffffffffffffffp0L, INFINITY, 0x1p1L, 0, l); 199143231Sdas testboth(0x1p1L, -INFINITY, 0x1.ffffffffffffffffffffffffffffp0L, 0, l); 200143231Sdas testboth(0x0.ffffffffffffffffffffffffffffp-16382L, INFINITY, 201143231Sdas 0x1p-16382L, 0, l); 202143231Sdas testboth(0x1p-16382L, -INFINITY, 203143231Sdas 0x0.ffffffffffffffffffffffffffffp-16382L, ex_under, l); 204143231Sdas#endif 205143231Sdas 206143231Sdas printf("ok 4 - next\n"); 207143231Sdas 208143231Sdas /* 209143231Sdas * Overflow tests 210143231Sdas */ 211143231Sdas test(idd(nextafter(DBL_MAX, INFINITY)), INFINITY, ex_over); 212143231Sdas test(idd(nextafter(INFINITY, 0.0)), DBL_MAX, 0); 213143231Sdas test(idd(nexttoward(DBL_MAX, DBL_MAX * 2.0L)), INFINITY, ex_over); 214143231Sdas test(idd(nexttoward(INFINITY, DBL_MAX * 2.0L)), DBL_MAX, 0); 215143231Sdas 216143231Sdas testf(idf(nextafterf(FLT_MAX, INFINITY)), INFINITY, ex_over); 217143231Sdas testf(idf(nextafterf(INFINITY, 0.0)), FLT_MAX, 0); 218143231Sdas testf(idf(nexttowardf(FLT_MAX, FLT_MAX * 2.0)), INFINITY, ex_over); 219143231Sdas testf(idf(nexttowardf(INFINITY, FLT_MAX * 2.0)), FLT_MAX, 0); 220143231Sdas 221174494Sdas testboth(ldbl_max, INFINITY, INFINITY, ex_over, l); 222174494Sdas testboth(INFINITY, 0.0, ldbl_max, 0, l); 223143231Sdas 224143231Sdas printf("ok 5 - next\n"); 225143231Sdas 226143231Sdas return (0); 227143231Sdas} 228143231Sdas 229143231Sdasstatic void 230143231Sdas_testl(const char *exp, int line, long double actual, long double expected, 231143231Sdas int except) 232143231Sdas{ 233143231Sdas int actual_except; 234143231Sdas 235143231Sdas actual_except = fetestexcept(ALL_STD_EXCEPT); 236143231Sdas if (actual != expected && !(isnan(actual) && isnan(expected))) { 237143231Sdas fprintf(stderr, "%d: %s returned %La, expecting %La\n", 238143231Sdas line, exp, actual, expected); 239143231Sdas abort(); 240143231Sdas } 241143231Sdas if (actual_except != except) { 242143231Sdas fprintf(stderr, "%d: %s raised 0x%x, expecting 0x%x\n", 243143231Sdas line, exp, actual_except, except); 244143231Sdas abort(); 245143231Sdas } 246143231Sdas} 247143231Sdas 248143231Sdas/* 249143231Sdas * The idd() and idf() routines ensure that doubles and floats are 250143231Sdas * converted to their respective types instead of stored in the FPU 251143231Sdas * with extra precision. 252143231Sdas */ 253143231Sdasstatic double 254143231Sdasidd(double x) 255143231Sdas{ 256143231Sdas return (x); 257143231Sdas} 258143231Sdas 259143231Sdasstatic float 260143231Sdasidf(float x) 261143231Sdas{ 262143231Sdas return (x); 263143231Sdas} 264