/* * SPDX-License-Identifier: BSD-3-Clause * * Copyright © 2020 Keith Packard * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ volatile FLOAT_T makemathname(zero) = 0.0; volatile FLOAT_T makemathname(negzero) = -0.0; volatile FLOAT_T makemathname(one) = 1.0; volatile FLOAT_T makemathname(two) = 2.0; volatile FLOAT_T makemathname(big) = BIG; volatile FLOAT_T makemathname(small) = SMALL; #define cat2(a,b) a ## b #define str(a) #a #define TEST(n,v,ex,er) { .func = makemathname(cat2(test_, n)), .name = str(n), .value = (v), .except = (ex), .errno_expect = (er) } static int _signgam; FLOAT_T makemathname(test_acos_2)(void) { return makemathname(acos)(makemathname(two)); } FLOAT_T makemathname(test_acosh_half)(void) { return makemathname(acosh)(makemathname(one)/makemathname(two)); } FLOAT_T makemathname(test_asin_2)(void) { return makemathname(asin)(makemathname(two)); } FLOAT_T makemathname(test_exp_big)(void) { return makemathname(exp)(makemathname(big)); } FLOAT_T makemathname(test_exp_neg)(void) { return makemathname(exp)(-makemathname(big)); } FLOAT_T makemathname(test_tgamma_0)(void) { return makemathname(tgamma)(makemathname(zero)); } FLOAT_T makemathname(test_tgamma_neg0)(void) { return makemathname(tgamma)(makemathname(negzero)); } FLOAT_T makemathname(test_tgamma_neg1)(void) { return makemathname(tgamma)(-makemathname(one)); } FLOAT_T makemathname(test_tgamma_big)(void) { return makemathname(tgamma)(makemathname(big)); } FLOAT_T makemathname(test_tgamma_negbig)(void) { return makemathname(tgamma)(makemathname(-big)); } FLOAT_T makemathname(test_tgamma_inf)(void) { return makemathname(tgamma)((FLOAT_T) INFINITY); } FLOAT_T makemathname(test_tgamma_neginf)(void) { return makemathname(tgamma)((FLOAT_T) -INFINITY); } FLOAT_T makemathname(test_tgamma_small)(void) { return makemathname(tgamma)(SMALL); } FLOAT_T makemathname(test_tgamma_negsmall)(void) { return makemathname(tgamma)(-SMALL); } FLOAT_T makemathname(test_hypot_big)(void) { return makemathname(hypot)(makemathname(big), makemathname(big)); } FLOAT_T makemathname(test_lgamma_0)(void) { return makemathname(lgamma)(makemathname(zero)); } FLOAT_T makemathname(test_lgamma_neg0)(void) { return makemathname(lgamma)(makemathname(negzero)); } FLOAT_T makemathname(test_lgamma_neg1)(void) { return makemathname(lgamma)(-makemathname(one)); } FLOAT_T makemathname(test_lgamma_big)(void) { return makemathname(lgamma)(makemathname(big)); } FLOAT_T makemathname(test_lgamma_negbig)(void) { return makemathname(lgamma)(makemathname(-big)); } FLOAT_T makemathname(test_lgamma_inf)(void) { return makemathname(lgamma)((FLOAT_T)INFINITY); } FLOAT_T makemathname(test_lgamma_neginf)(void) { return makemathname(lgamma)(-(FLOAT_T)INFINITY); } FLOAT_T makemathname(test_lgamma_r_0)(void) { return makemathname_r(lgamma)(makemathname(zero),&_signgam); } FLOAT_T makemathname(test_lgamma_r_neg0)(void) { return makemathname_r(lgamma)(makemathname(negzero),&_signgam); } FLOAT_T makemathname(test_lgamma_r_neg1)(void) { return makemathname_r(lgamma)(-makemathname(one),&_signgam); } FLOAT_T makemathname(test_lgamma_r_big)(void) { return makemathname_r(lgamma)(makemathname(big),&_signgam); } FLOAT_T makemathname(test_lgamma_r_negbig)(void) { return makemathname_r(lgamma)(makemathname(-big),&_signgam); } FLOAT_T makemathname(test_lgamma_r_inf)(void) { return makemathname_r(lgamma)((FLOAT_T)INFINITY,&_signgam); } FLOAT_T makemathname(test_lgamma_r_neginf)(void) { return makemathname_r(lgamma)(-(FLOAT_T)INFINITY,&_signgam); } FLOAT_T makemathname(test_gamma_0)(void) { return makemathname(gamma)(makemathname(zero)); } FLOAT_T makemathname(test_gamma_neg0)(void) { return makemathname(gamma)(makemathname(negzero)); } FLOAT_T makemathname(test_gamma_neg1)(void) { return makemathname(gamma)(-makemathname(one)); } FLOAT_T makemathname(test_gamma_big)(void) { return makemathname(gamma)(makemathname(big)); } FLOAT_T makemathname(test_gamma_negbig)(void) { return makemathname(gamma)(makemathname(-big)); } FLOAT_T makemathname(test_gamma_inf)(void) { return makemathname(gamma)((FLOAT_T)INFINITY); } FLOAT_T makemathname(test_gamma_neginf)(void) { return makemathname(gamma)(-(FLOAT_T)INFINITY); } FLOAT_T makemathname(test_log_0)(void) { return makemathname(log)(makemathname(zero)); } FLOAT_T makemathname(test_log_neg)(void) { return makemathname(log)(-makemathname(one)); } FLOAT_T makemathname(test_log10_0)(void) { return makemathname(log10)(makemathname(zero)); } FLOAT_T makemathname(test_log10_neg)(void) { return makemathname(log10)(-makemathname(one)); } FLOAT_T makemathname(test_pow_neg_real)(void) { return makemathname(pow)(-makemathname(two), makemathname(one)/makemathname(two)); } FLOAT_T makemathname(test_pow_0_neg)(void) { return makemathname(pow)(makemathname(zero), -makemathname(two)); } FLOAT_T makemathname(test_pow_big)(void) { return makemathname(pow)(makemathname(two), makemathname(big)); } FLOAT_T makemathname(test_pow_tiny)(void) { return makemathname(pow)(makemathname(two), -makemathname(big)); } FLOAT_T makemathname(test_remainder_0)(void) { return makemathname(remainder)(makemathname(two), makemathname(zero)); } FLOAT_T makemathname(test_sqrt_neg)(void) { return makemathname(sqrt)(-makemathname(two)); } FLOAT_T makemathname(test_y0_0)(void) { return makemathname(y0)(makemathname(zero)); } FLOAT_T makemathname(test_y0_neg)(void) { return makemathname(y0)(-makemathname(one)); } FLOAT_T makemathname(test_y1_0)(void) { return makemathname(y1)(makemathname(zero)); } FLOAT_T makemathname(test_y1_neg)(void) { return makemathname(y1)(-makemathname(one)); } FLOAT_T makemathname(test_yn_0)(void) { return makemathname(yn)(2, makemathname(zero)); } FLOAT_T makemathname(test_yn_neg)(void) { return makemathname(yn)(2, -makemathname(one)); } struct { FLOAT_T (*func)(void); char *name; FLOAT_T value; int except; int errno_expect; } makemathname(tests)[] = { TEST(acos_2, (FLOAT_T) NAN, FE_INVALID, EDOM), TEST(acosh_half, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(asin_2, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(exp_big, (FLOAT_T)INFINITY, FE_OVERFLOW, ERANGE), TEST(exp_neg, (FLOAT_T)0.0, FE_UNDERFLOW, ERANGE), TEST(hypot_big, (FLOAT_T)INFINITY, FE_OVERFLOW, ERANGE), TEST(tgamma_0, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(tgamma_neg0, -(FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(tgamma_neg1, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(tgamma_big, (FLOAT_T)INFINITY, FE_OVERFLOW, ERANGE), TEST(tgamma_negbig, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(tgamma_inf, (FLOAT_T)INFINITY, 0, 0), TEST(tgamma_neginf, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(tgamma_small, (FLOAT_T)INFINITY, FE_OVERFLOW, ERANGE), TEST(tgamma_negsmall, -(FLOAT_T)INFINITY, FE_OVERFLOW, ERANGE), TEST(lgamma_0, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(lgamma_neg0, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(lgamma_neg1, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(lgamma_big, (FLOAT_T)INFINITY, FE_OVERFLOW, ERANGE), TEST(lgamma_negbig, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(lgamma_inf, (FLOAT_T)INFINITY, 0, 0), TEST(lgamma_neginf, (FLOAT_T)INFINITY, 0, 0), TEST(lgamma_r_0, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(lgamma_r_neg0, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(lgamma_r_neg1, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(lgamma_r_big, (FLOAT_T)INFINITY, FE_OVERFLOW, ERANGE), TEST(lgamma_r_negbig, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(lgamma_r_inf, (FLOAT_T)INFINITY, 0, 0), TEST(lgamma_r_neginf, (FLOAT_T)INFINITY, 0, 0), TEST(gamma_0, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(gamma_neg0, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(gamma_neg1, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(gamma_big, (FLOAT_T)INFINITY, FE_OVERFLOW, ERANGE), TEST(gamma_negbig, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(gamma_inf, (FLOAT_T)INFINITY, 0, 0), TEST(gamma_neginf, (FLOAT_T)INFINITY, 0, 0), TEST(log_0, -(FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(log_neg, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(log10_0, -(FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(log10_neg, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(pow_neg_real, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(pow_0_neg, (FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(pow_big, (FLOAT_T)INFINITY, FE_OVERFLOW, ERANGE), TEST(pow_tiny, (FLOAT_T)0.0, FE_UNDERFLOW, ERANGE), TEST(remainder_0, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(sqrt_neg, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(y0_0, -(FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(y0_neg, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(y1_0, -(FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(y1_neg, (FLOAT_T)NAN, FE_INVALID, EDOM), TEST(yn_0, -(FLOAT_T)INFINITY, FE_DIVBYZERO, ERANGE), TEST(yn_neg, (FLOAT_T)NAN, FE_INVALID, EDOM), { NULL, NULL }, }; int makemathname(run_tests)(void) { int result = 0; volatile FLOAT_T v; int err, except; int t; for (t = 0; makemathname(tests)[t].func; t++) { errno = 0; feclearexcept(FE_ALL_EXCEPT); v = makemathname(tests)[t].func(); err = errno; except = fetestexcept(FE_ALL_EXCEPT); #if defined(TINY_STDIO) || !defined(NO_FLOATING_POINT) printf(" %-20.20s = %g errno %d (%s) except 0x%x\n", makemathname(tests)[t].name, (double) v, err, strerror(err), except); #else printf(" %-20.20s = (float) errno %d (%s) except 0x%x\n", makemathname(tests)[t].name, err, strerror(err), except); #endif if ((isinf(v) && isinf(makemathname(tests)[t].value) && ((v > 0) != (makemathname(tests)[t].value > 0))) || (v != makemathname(tests)[t].value && isnanf(v) != isnanf(makemathname(tests)[t].value))) { printf("\tbad value got %g expect %g\n", (double) v, (double) makemathname(tests)[t].value); ++result; } if (math_errhandling & EXCEPTION_TEST) { if ((except & makemathname(tests)[t].except) != makemathname(tests)[t].except) { printf("\texceptions supported but %s returns 0x%x\n", makemathname(tests)[t].name, except); ++result; } } else { if (except) { printf("\texceptions not supported but %s returns 0x%x\n", makemathname(tests)[t].name, except); ++result; } } if (math_errhandling & MATH_ERRNO) { if (err != makemathname(tests)[t].errno_expect) { printf("\terrno supported but %s returns %d (%s)\n", makemathname(tests)[t].name, err, strerror(err)); ++result; } } else { if (err != 0) { printf("\terrno not supported but %s returns %d (%s)\n", makemathname(tests)[t].name, err, strerror(err)); ++result; } } } return result; }