diff options
author | Waldemar Brodkorb <wbx@uclibc-ng.org> | 2016-10-24 20:22:12 +0200 |
---|---|---|
committer | Waldemar Brodkorb <wbx@uclibc-ng.org> | 2016-10-24 20:22:12 +0200 |
commit | 7988979a722b4cdf287b2093956a76a3f19b9897 (patch) | |
tree | d35e251d0472ceca55a2eef61cff261c8ee68fab /test/math |
add uClibc-ng test directory
Diffstat (limited to 'test/math')
35 files changed, 29783 insertions, 0 deletions
diff --git a/test/math/Makefile b/test/math/Makefile new file mode 100644 index 0000000..6194efa --- /dev/null +++ b/test/math/Makefile @@ -0,0 +1,8 @@ +# uClibc math tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +top_builddir=../../ +top_srcdir=../../ +include ../Rules.mak +-include Makefile.in +include ../Test.mak diff --git a/test/math/Makefile.in b/test/math/Makefile.in new file mode 100644 index 0000000..3874001 --- /dev/null +++ b/test/math/Makefile.in @@ -0,0 +1,46 @@ +# uClibc math tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +# libm-test.c is a generated file used by the tests internally so skip it +TESTS_DISABLED := libm-test + +# gamma (removed from TESTS, need to add "small errors are ok" machinery there) +TESTS_DISABLED += gamma +ifeq ($(UCLIBC_HAS_LONG_DOUBLE_MATH),) +TESTS_DISABLED += test-ldouble test-ildoubl compile_test c99_test +CFLAGS_basic-test := -DNO_LONG_DOUBLE +endif +ifeq ($(DO_C99_MATH),) +TESTS_DISABLED += test-float test-ifloat test-double test-idouble rint signgam ilogb +endif +ifeq ($(UCLIBC_HAS_FPU),) +TESTS_DISABLED += test-fpucw +endif + +DODIFF_rint := 1 +DODIFF_signgam := 1 + +# NOTE: For basic-test we must disable the floating point optimization. +# Only for sh architecture because in the other architecture are disabled. +ifeq ($(TARGET_ARCH),sh) +CFLAGS_basic-test += -mieee +endif +EXTRA_CFLAGS := -fno-builtin +EXTRA_LDFLAGS := -lm + +PERL := perl + +MDEPS := $(wildcard test-*.c) +$(MDEPS): libm-test.c + +ULP_SUFFIX := +ifeq ($(TARGET_ARCH),mips) +ULP_SUFFIX:=$(if $(CONFIG_MIPS_N64_ABI),64,32) +endif + +TARGET_ULP := $(if $(wildcard libm-test-ulps-$(TARGET_ARCH)$(ULP_SUFFIX)),$(TARGET_ARCH)$(ULP_SUFFIX),generic) + +libm-test.c: libm-test-ulps-$(TARGET_ULP) libm-test.inc gen-libm-test.pl + $(Q)$(PERL) ./gen-libm-test.pl -u libm-test-ulps-$(TARGET_ULP) ./libm-test.inc -o "." 2>&1 > /dev/null + +EXTRA_CLEAN := libm-test.c libm-test-ulps.h diff --git a/test/math/basic-test.c b/test/math/basic-test.c new file mode 100644 index 0000000..d073abb --- /dev/null +++ b/test/math/basic-test.c @@ -0,0 +1,161 @@ +/* Copyright (C) 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Andreas Jaeger <aj@suse.de>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define _ISOC99_SOURCE + +#include <math.h> +#include <float.h> +#include <stdio.h> + +static int errors = 0; + + +static void +check (const char *testname, int result) +{ + if (!result) { + printf ("Failure: %s\n", testname); + errors++; + } +} + +#define TEST_FUNC(NAME, FLOAT, NANFUNC, EPSILON, HUGEVAL) \ +static void \ +NAME (void) \ +{ \ + /* Variables are declared volatile to forbid some compiler \ + optimizations. */ \ + volatile FLOAT Inf_var, NaN_var, zero_var, one_var; \ + FLOAT x1, x2; \ + \ + zero_var = 0.0; \ + one_var = 1.0; \ + NaN_var = zero_var/zero_var; \ + Inf_var = one_var / zero_var; \ + \ + (void) &zero_var; \ + (void) &one_var; \ + (void) &NaN_var; \ + (void) &Inf_var; \ + \ + \ + check (#FLOAT " isinf (inf) == 1", isinf (Inf_var) == 1); \ + check (#FLOAT " isinf (-inf) == -1", isinf (-Inf_var) == -1); \ + check (#FLOAT " !isinf (1)", !(isinf (one_var))); \ + check (#FLOAT " !isinf (NaN)", !(isinf (NaN_var))); \ + \ + check (#FLOAT " isnan (NaN)", isnan (NaN_var)); \ + check (#FLOAT " isnan (-NaN)", isnan (-NaN_var)); \ + check (#FLOAT " !isnan (1)", !(isnan (one_var))); \ + check (#FLOAT " !isnan (inf)", !(isnan (Inf_var))); \ + \ + /* \ + the same tests but this time with NAN from <bits/nan.h> \ + NAN is a double const \ + */ \ + check (#FLOAT " isnan (NAN)", isnan (NAN)); \ + check (#FLOAT " isnan (-NAN)", isnan (-NAN)); \ + check (#FLOAT " !isinf (NAN)", !(isinf (NAN))); \ + check (#FLOAT " !isinf (-NAN)", !(isinf (-NAN))); \ + \ + /* \ + And again with the value returned by the `nan' function. \ + */ \ + check (#FLOAT " isnan (NAN)", isnan (NANFUNC (""))); \ + check (#FLOAT " isnan (-NAN)", isnan (-NANFUNC (""))); \ + check (#FLOAT " !isinf (NAN)", !(isinf (NANFUNC ("")))); \ + check (#FLOAT " !isinf (-NAN)", !(isinf (-NANFUNC ("")))); \ + check (#FLOAT " NAN != NAN", NANFUNC ("") != NANFUNC ("")); \ + \ + /* test if HUGE_VALx is ok */ \ + x1 = HUGEVAL; \ + check (#FLOAT " isinf (HUGE_VALx) == +1", isinf (x1) == +1); \ + x1 = - HUGEVAL; \ + check (#FLOAT " isinf (-HUGE_VALx) == -1", isinf (x1) == -1); \ +} +#ifndef DO_C99_MATH +# undef TEST_FUNC +# define TEST_FUNC(NAME, FLOAT, NANFUNC, EPSILON, HUGEVAL) \ +static void \ +NAME(void) \ +{ /* nothing */ } +#endif + +#define TEST_VAL(NAME, FLOAT, NANFUNC, EPSILON, HUGEVAL) \ +static void \ +NAME (void) \ +{ \ + /* Variables are declared volatile to forbid some compiler \ + optimizations. */ \ + volatile FLOAT Inf_var, NaN_var, zero_var, one_var; \ + FLOAT x1, x2; \ + \ + zero_var = 0.0; \ + one_var = 1.0; \ + NaN_var = zero_var/zero_var; \ + Inf_var = one_var / zero_var; \ + \ + (void) &zero_var; \ + (void) &one_var; \ + (void) &NaN_var; \ + (void) &Inf_var; \ + \ + \ + check (#FLOAT " inf == inf", Inf_var == Inf_var); \ + check (#FLOAT " -inf == -inf", -Inf_var == -Inf_var); \ + check (#FLOAT " inf != -inf", Inf_var != -Inf_var); \ + check (#FLOAT " NaN != NaN", NaN_var != NaN_var); \ + \ + check (#FLOAT " NAN != NAN", NAN != NAN); \ + \ + \ + /* test if EPSILON is ok */ \ + x1 = 1.0; \ + x2 = x1 + EPSILON; \ + check (#FLOAT " 1 != 1+EPSILON", x1 != x2); \ + \ + x1 = 1.0; \ + x2 = x1 - EPSILON; \ + check (#FLOAT " 1 != 1-EPSILON", x1 != x2); \ + \ +} + +TEST_VAL (float_test_value, float, nanf, FLT_EPSILON, HUGE_VALF) +TEST_FUNC (float_test_call, float, nanf, FLT_EPSILON, HUGE_VALF) +TEST_VAL (double_test_value, double, nan, DBL_EPSILON, HUGE_VAL) +TEST_FUNC (double_test_call, double, nan, DBL_EPSILON, HUGE_VAL) +#ifndef NO_LONG_DOUBLE +TEST_VAL (ldouble_test_value, long double, nanl, LDBL_EPSILON, HUGE_VALL) +TEST_FUNC (ldouble_test_call, long double, nanl, LDBL_EPSILON, HUGE_VALL) +#endif + +int +main (void) +{ + float_test_value (); + float_test_call (); + double_test_value (); + double_test_call (); + +#ifndef NO_LONG_DOUBLE + ldouble_test_value (); + ldouble_test_call (); +#endif + + return errors != 0; +} diff --git a/test/math/c99_test.c b/test/math/c99_test.c new file mode 100644 index 0000000..73382e4 --- /dev/null +++ b/test/math/c99_test.c @@ -0,0 +1,116 @@ +#include <math.h> +#include <float.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include <stdio.h> + +#define check_d1(func, param, expected) \ +do { \ + int err; hex_union ur; hex_union up; \ + double result = func(param); up.f = param; ur.f = result; \ + errors += (err = (result != (expected))); \ + err \ + ? printf("FAIL: %s(%g/"HEXFMT")=%g/"HEXFMT" (expected %g)\n", \ + #func, (double)(param), (long long)up.hex, result, (long long)ur.hex, (double)(expected)) \ + : printf("PASS: %s(%g)=%g\n", #func, (double)(param), result); \ +} while (0) + +#define check_i1(func, param, expected) \ +do { \ + int err; hex_union up; \ + long long result = func(param); up.f = param; \ + errors += (err = (result != (expected))); \ + err \ + ? printf("FAIL: %s(%g/"HEXFMT")=%lld/%llu (expected %llu)\n", \ + #func, (double)(param), (long long)up.hex, result, result, (long long)(expected)) \ + : printf("PASS: %s(%g)=%lld/%llu\n", #func, (double)(param), result, result); \ +} while (0) + +#define HEXFMT "%08llx" +typedef union { + double f; + uint64_t hex; +} hex_union; + +double zero = 0.0; +double minus_zero = 0.0; +double nan_value = 0.0; +int errors = 0; + +int main(void) +{ + nan_value /= nan_value; + minus_zero = copysign(zero, -1.0); + + check_i1(isfinite, 1.0, 1); + check_i1(isfinite, 2.0, 1); + check_i1(isfinite, 3.0, 1); + check_i1(isfinite, DBL_MAX, 1); + check_i1(isfinite, FLT_MAX, 1); + check_i1(isfinite, HUGE_VAL, 0); + check_i1(isfinite, HUGE_VALF, 0); + check_i1(isfinite, HUGE_VALL, 0); + check_i1(isfinite, nan_value, 0); + check_i1(isfinite, nan_value, 0); + check_i1(isfinite, nan_value, 0); + + check_i1(isnan, 1.0, 0); + check_i1(isnan, 2.0, 0); + check_i1(isnan, 3.0, 0); + check_i1(isnan, DBL_MAX, 0); + check_i1(isnan, FLT_MAX, 0); + check_i1(isnan, HUGE_VAL, 0); + check_i1(isnan, HUGE_VALF, 0); + check_i1(isnan, HUGE_VALL, 0); + check_i1(isnan, (float)HUGE_VALL, 0); + check_i1(isnan, nan_value, 1); + check_i1(isnan, nan_value, 1); + check_i1(isnan, nan_value, 1); + + check_i1(isinf, 1.0, 0); + check_i1(isinf, 2.0, 0); + check_i1(isinf, 3.0, 0); + check_i1(isinf, DBL_MAX, 0); + check_i1(isinf, FLT_MAX, 0); + check_i1(isinf, (float)DBL_MAX, 1); + check_i1(isinf, HUGE_VAL, 1); + check_i1(isinf, HUGE_VALF, 1); + check_i1(isinf, HUGE_VALL, 1); + check_i1(isinf, (float)HUGE_VALL, 1); + check_i1(isinf, nan_value, 0); + check_i1(isinf, nan_value, 0); + check_i1(isinf, nan_value, 0); + + check_i1(fpclassify, minus_zero, FP_ZERO); + check_i1(fpclassify, 0.0, FP_ZERO); + check_i1(fpclassify, 1.0, FP_NORMAL); + check_i1(fpclassify, 2.0, FP_NORMAL); + check_i1(fpclassify, 3.0, FP_NORMAL); + check_i1(fpclassify, DBL_MIN/1.01, FP_SUBNORMAL); + check_i1(fpclassify, DBL_MIN, FP_NORMAL); + check_i1(fpclassify, DBL_MAX, FP_NORMAL); + check_i1(fpclassify, FLT_MAX, FP_NORMAL); + check_i1(fpclassify, DBL_MAX, FP_NORMAL); + check_i1(fpclassify, DBL_MAX*1.01, FP_INFINITE); + check_i1(fpclassify, HUGE_VAL, FP_INFINITE); + check_i1(fpclassify, HUGE_VALF, FP_INFINITE); + check_i1(fpclassify, HUGE_VALL, FP_INFINITE); + check_i1(fpclassify, (float)HUGE_VALL, FP_INFINITE); + check_i1(fpclassify, nan_value, FP_NAN); + check_i1(fpclassify, nan_value, FP_NAN); + check_i1(fpclassify, nan_value, FP_NAN); + + check_i1(!!signbit, -1.0, 1); + check_i1(!!signbit, minus_zero, 1); + check_i1(!!signbit, 0.0, 0); + check_i1(!!signbit, HUGE_VAL, 0); + check_i1(!!signbit, HUGE_VALF, 0); + check_i1(!!signbit, HUGE_VALL, 0); + check_i1(!!signbit, -HUGE_VAL, 1); + check_i1(!!signbit, -HUGE_VALF, 1); + check_i1(!!signbit, -HUGE_VALL, 1); + + printf("Errors: %d\n", errors); + return errors; +} diff --git a/test/math/compile_test.c b/test/math/compile_test.c new file mode 100644 index 0000000..aedfde6 --- /dev/null +++ b/test/math/compile_test.c @@ -0,0 +1,141 @@ +#include <math.h> + +static int testf(float float_x, long double long_double_x, /*float complex float_complex_x,*/ int int_x, long long_x) +{ +int r = 0; +r += acosf(float_x); +r += acoshf(float_x); +r += asinf(float_x); +r += asinhf(float_x); +r += atan2f(float_x, float_x); +r += atanf(float_x); +r += atanhf(float_x); +/*r += cargf(float_complex_x); - will fight with complex numbers later */ +r += cbrtf(float_x); +r += ceilf(float_x); +r += copysignf(float_x, float_x); +r += cosf(float_x); +r += coshf(float_x); +r += erfcf(float_x); +r += erff(float_x); +r += exp2f(float_x); +r += expf(float_x); +r += expm1f(float_x); +r += fabsf(float_x); +r += fdimf(float_x, float_x); +r += floorf(float_x); +r += fmaf(float_x, float_x, float_x); +r += fmaxf(float_x, float_x); +r += fminf(float_x, float_x); +r += fmodf(float_x, float_x); +r += frexpf(float_x, &int_x); +r += gammaf(float_x); +r += hypotf(float_x, float_x); +r += ilogbf(float_x); +r += ldexpf(float_x, int_x); +r += lgammaf(float_x); +r += llrintf(float_x); +r += llroundf(float_x); +r += log10f(float_x); +r += log1pf(float_x); +r += log2f(float_x); +r += logbf(float_x); +r += logf(float_x); +r += lrintf(float_x); +r += lroundf(float_x); +r += modff(float_x, &float_x); +r += nearbyintf(float_x); +r += nexttowardf(float_x, long_double_x); +r += powf(float_x, float_x); +r += remainderf(float_x, float_x); +r += remquof(float_x, float_x, &int_x); +r += rintf(float_x); +r += roundf(float_x); +#ifdef __UCLIBC_SUSV3_LEGACY__ +r += scalbf(float_x, float_x); +#endif +r += scalblnf(float_x, long_x); +r += scalbnf(float_x, int_x); +r += significandf(float_x); +r += sinf(float_x); +r += sinhf(float_x); +r += sqrtf(float_x); +r += tanf(float_x); +r += tanhf(float_x); +r += tgammaf(float_x); +r += truncf(float_x); +return r; +} + +static int testl(long double long_double_x, int int_x, long long_x) +{ +int r = 0; +r += __finitel(long_double_x); +r += __fpclassifyl(long_double_x); +r += __isinfl(long_double_x); +r += __isnanl(long_double_x); +r += __signbitl(long_double_x); +r += acoshl(long_double_x); +r += acosl(long_double_x); +r += asinhl(long_double_x); +r += asinl(long_double_x); +r += atan2l(long_double_x, long_double_x); +r += atanhl(long_double_x); +r += atanl(long_double_x); +r += cbrtl(long_double_x); +r += ceill(long_double_x); +r += copysignl(long_double_x, long_double_x); +r += coshl(long_double_x); +r += cosl(long_double_x); +r += erfcl(long_double_x); +r += erfl(long_double_x); +r += exp2l(long_double_x); +r += expl(long_double_x); +r += expm1l(long_double_x); +r += fabsl(long_double_x); +r += fdiml(long_double_x, long_double_x); +r += floorl(long_double_x); +r += fmal(long_double_x, long_double_x, long_double_x); +r += fmaxl(long_double_x, long_double_x); +r += fminl(long_double_x, long_double_x); +r += fmodl(long_double_x, long_double_x); +r += frexpl(long_double_x, &int_x); +r += hypotl(long_double_x, long_double_x); +r += ilogbl(long_double_x); +r += ldexpl(long_double_x, int_x); +r += lgammal(long_double_x); +r += llrintl(long_double_x); +r += llroundl(long_double_x); +r += log10l(long_double_x); +r += log1pl(long_double_x); +r += log2l(long_double_x); +r += logbl(long_double_x); +r += logl(long_double_x); +r += lrintl(long_double_x); +r += lroundl(long_double_x); +r += modfl(long_double_x, &long_double_x); +r += nearbyintl(long_double_x); +r += nextafterl(long_double_x, long_double_x); +r += nexttowardl(long_double_x, long_double_x); +r += powl(long_double_x, long_double_x); +r += remainderl(long_double_x, long_double_x); +r += remquol(long_double_x, long_double_x, &int_x); +r += rintl(long_double_x); +r += roundl(long_double_x); +r += scalblnl(long_double_x, long_x); +r += scalbnl(long_double_x, int_x); +r += sinhl(long_double_x); +r += sinl(long_double_x); +r += sqrtl(long_double_x); +r += tanhl(long_double_x); +r += tanl(long_double_x); +r += tgammal(long_double_x); +r += truncl(long_double_x); +return r; +} + +int main(int argc, char **argv) +{ + /* Always 0 but gcc hopefully won't be able to notice */ + return 5 & ((long)&testf) & ((long)&testl) & 2; +} diff --git a/test/math/fenv.h b/test/math/fenv.h new file mode 100644 index 0000000..0025a62 --- /dev/null +++ b/test/math/fenv.h @@ -0,0 +1,3 @@ +/* until we support fenv ... */ +#define feclearexcept(X) +#define fetestexcept(X) (0) diff --git a/test/math/gamma.c b/test/math/gamma.c new file mode 100644 index 0000000..69c10af --- /dev/null +++ b/test/math/gamma.c @@ -0,0 +1,73 @@ +#include <math.h> +#include <float.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> + +#define check_d1(func, param, expected) \ +do { \ + int err; hex_union ur; hex_union up; \ + double result = func(param); up.f = param; ur.f = result; \ + errors += (err = (result != (expected))); \ + err \ + ? printf("FAIL: %s(%g/"HEXFMT")=%g/"HEXFMT" (expected %g)\n", \ + #func, (double)(param), (long long)up.hex, result, (long long)ur.hex, (double)(expected)) \ + : printf("PASS: %s(%g)=%g\n", #func, (double)(param), result); \ +} while (0) + +#define HEXFMT "%08llx" +typedef union { + double f; + uint64_t hex; +} hex_union; +double result; + +#define M_2_SQRT_PIl 3.5449077018110320545963349666822903L /* 2 sqrt (M_PIl) */ +#define M_SQRT_PIl 1.7724538509055160272981674833411451L /* sqrt (M_PIl) */ + +double zero = 0.0; +double minus_zero = 0.0; +double nan_value = 0.0; +int errors = 0; + +int main(void) +{ + nan_value /= nan_value; + minus_zero = copysign(zero, -1.0); + + //check_d1(tgamma, HUGE_VAL, NAN); + //check_d1(tgamma, negative_integer, NAN); + check_d1(tgamma, 0.0, HUGE_VAL); /* pole */ + check_d1(tgamma, minus_zero, -HUGE_VAL); /* pole */ + check_d1(tgamma, DBL_MAX/2, HUGE_VAL); /* overflow to inf */ + check_d1(tgamma, DBL_MAX, HUGE_VAL); /* overflow to inf */ + check_d1(tgamma, HUGE_VAL, HUGE_VAL); /* overflow to inf */ + check_d1(tgamma, 7, 2*3*4*5*6); /* normal value */ + check_d1(tgamma, -0.5, -M_2_SQRT_PIl); /* normal value (testing negative points) */ + + check_d1(lgamma, -HUGE_VAL, HUGE_VAL); + //check_d1(lgamma, HUGE_VAL, NAN); + check_d1(lgamma, 0.0, HUGE_VAL); /* pole */ + check_d1(lgamma, minus_zero, HUGE_VAL); /* pole */ + check_d1(lgamma, 1.0, 0.0); + check_d1(lgamma, 2.0, 0.0); + check_d1(lgamma, DBL_MAX/2, HUGE_VAL); /* overflow to inf */ + check_d1(lgamma, DBL_MAX, HUGE_VAL); /* overflow to inf */ + check_d1(lgamma, HUGE_VAL, HUGE_VAL); /* overflow to inf */ + check_d1(lgamma, 7, log(2*3*4*5*6)); /* normal value */ + + /* In glibc, gamma == lgamma. (In BSD, it's == tgamma */ + check_d1(gamma, -HUGE_VAL, HUGE_VAL); + //check_d1(gamma, HUGE_VAL, NAN); + check_d1(gamma, 0.0, HUGE_VAL); /* pole */ + check_d1(gamma, minus_zero, HUGE_VAL); /* pole */ + check_d1(gamma, 1.0, 0.0); + check_d1(gamma, 2.0, 0.0); + check_d1(gamma, DBL_MAX/2, HUGE_VAL); /* overflow to inf */ + check_d1(gamma, DBL_MAX, HUGE_VAL); /* overflow to inf */ + check_d1(gamma, HUGE_VAL, HUGE_VAL); /* overflow to inf */ + check_d1(gamma, 7, log(2*3*4*5*6)); /* normal value */ + + printf("Errors: %d\n", errors); + return errors; +} diff --git a/test/math/gen-libm-test.pl b/test/math/gen-libm-test.pl new file mode 100755 index 0000000..118f352 --- /dev/null +++ b/test/math/gen-libm-test.pl @@ -0,0 +1,737 @@ +#!/usr/bin/env perl +# Copyright (C) 1999 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# Contributed by Andreas Jaeger <aj@suse.de>, 1999. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; see the file COPYING.LIB. If +# not, see <http://www.gnu.org/licenses/>. + +# This file needs to be tidied up +# Note that functions and tests share the same namespace. + +# Information about tests are stored in: %results +# $results{$test}{"kind"} is either "fct" or "test" and flags whether this +# is a maximal error of a function or a single test. +# $results{$test}{"type"} is the result type, e.g. normal or complex. +# $results{$test}{"has_ulps"} is set if deltas exist. +# $results{$test}{"has_fails"} is set if exptected failures exist. +# In the following description $type and $float are: +# - $type is either "normal", "real" (for the real part of a complex number) +# or "imag" (for the imaginary part # of a complex number). +# - $float is either of float, ifloat, double, idouble, ldouble, ildouble; +# It represents the underlying floating point type (float, double or long +# double) and if inline functions (the leading i stands for inline) +# are used. +# $results{$test}{$type}{"fail"}{$float} is defined and has a 1 if +# the test is expected to fail +# $results{$test}{$type}{"ulp"}{$float} is defined and has a delta as value + + +use Getopt::Std; + +use strict; + +use vars qw ($input $output); +use vars qw (%results); +use vars qw (@tests @functions); +use vars qw ($count); +use vars qw (%beautify @all_floats); +use vars qw ($output_dir $ulps_file); + +# all_floats is sorted and contains all recognised float types +@all_floats = ('double', 'float', 'idouble', + 'ifloat', 'ildouble', 'ldouble'); + +%beautify = + ( "minus_zero" => "-0", + "plus_zero" => "+0", + "minus_infty" => "-inf", + "plus_infty" => "inf", + "nan_value" => "NaN", + "M_El" => "e", + "M_E2l" => "e^2", + "M_E3l" => "e^3", + "M_LOG10El", "log10(e)", + "M_PIl" => "pi", + "M_PI_34l" => "3/4 pi", + "M_PI_2l" => "pi/2", + "M_PI_4l" => "pi/4", + "M_PI_6l" => "pi/6", + "M_PI_34_LOG10El" => "3/4 pi*log10(e)", + "M_PI_LOG10El" => "pi*log10(e)", + "M_PI2_LOG10El" => "pi/2*log10(e)", + "M_PI4_LOG10El" => "pi/4*log10(e)", + "M_LOG_SQRT_PIl" => "log(sqrt(pi))", + "M_LOG_2_SQRT_PIl" => "log(2*sqrt(pi))", + "M_2_SQRT_PIl" => "2 sqrt (pi)", + "M_SQRT_PIl" => "sqrt (pi)", + "INVALID_EXCEPTION" => "invalid exception", + "DIVIDE_BY_ZERO_EXCEPTION" => "division by zero exception", + "INVALID_EXCEPTION_OK" => "invalid exception allowed", + "DIVIDE_BY_ZERO_EXCEPTION_OK" => "division by zero exception allowed", + "EXCEPTIONS_OK" => "exceptions allowed", + "IGNORE_ZERO_INF_SIGN" => "sign of zero/inf not specified", +"INVALID_EXCEPTION|IGNORE_ZERO_INF_SIGN" => "invalid exception and sign of zero/inf not specified" + ); + + +# get Options +# Options: +# u: ulps-file +# h: help +# o: output-directory +# n: generate new ulps file +use vars qw($opt_u $opt_h $opt_o $opt_n); +getopts('u:o:nh'); + +$ulps_file = 'libm-test-ulps'; +$output_dir = ''; + +if ($opt_h) { + print "Usage: gen-libm-test.pl [OPTIONS]\n"; + print " -h print this help, then exit\n"; + print " -o DIR directory where generated files will be placed\n"; + print " -n only generate sorted file NewUlps from libm-test-ulps\n"; + print " -u FILE input file with ulps\n"; + exit 0; +} + +$ulps_file = $opt_u if ($opt_u); +$output_dir = $opt_o if ($opt_o); + +$input = "libm-test.inc"; +$output = "${output_dir}libm-test.c"; + +$count = 0; + +&parse_ulps ($ulps_file); +&generate_testfile ($input, $output) unless ($opt_n); +&output_ulps ("${output_dir}libm-test-ulps.h", $ulps_file) unless ($opt_n); +&print_ulps_file ("${output_dir}NewUlps") if ($opt_n); + +# Return a nicer representation +sub beautify { + my ($arg) = @_; + my ($tmp); + + if (exists $beautify{$arg}) { + return $beautify{$arg}; + } + if ($arg =~ /^-/) { + $tmp = $arg; + $tmp =~ s/^-//; + if (exists $beautify{$tmp}) { + return '-' . $beautify{$tmp}; + } + } + if ($arg =~ /[0-9]L$/) { + $arg =~ s/L$//; + } + return $arg; +} + +# Return a nicer representation of a complex number +sub build_complex_beautify { + my ($r, $i) = @_; + my ($str1, $str2); + + $str1 = &beautify ($r); + $str2 = &beautify ($i); + if ($str2 =~ /^-/) { + $str2 =~ s/^-//; + $str1 .= ' - ' . $str2; + } else { + $str1 .= ' + ' . $str2; + } + $str1 .= ' i'; + return $str1; +} + +# Return name of a variable +sub get_variable { + my ($number) = @_; + + return "x" if ($number == 1); + return "y" if ($number == 2); + return "z" if ($number == 3); + # return x1,x2,... + $number =-3; + return "x$number"; +} + +# Add a new test to internal data structures and fill in the +# ulps, failures and exception information for the C line. +sub new_test { + my ($test, $exception) = @_; + my $rest; + + # Add ulp, xfail + if (exists $results{$test}{'has_ulps'}) { + $rest = ", DELTA$count"; + } else { + $rest = ', 0'; + } + if (exists $results{$test}{'has_fails'}) { + $rest .= ", FAIL$count"; + } else { + $rest .= ', 0'; + } + if (defined $exception) { + $rest .= ", $exception"; + } else { + $rest .= ', 0'; + } + $rest .= ");\n"; + # We must increment here to keep @tests and count in sync + push @tests, $test; + ++$count; + return $rest; +} + +# Treat some functions especially. +# Currently only sincos needs extra treatment. +sub special_functions { + my ($file, $args) = @_; + my (@args, $str, $test, $cline); + + @args = split /,\s*/, $args; + + unless ($args[0] =~ /sincos/) { + die ("Don't know how to handle $args[0] extra."); + } + print $file " FUNC (sincos) ($args[1], &sin_res, &cos_res);\n"; + + $str = 'sincos (' . &beautify ($args[1]) . ', &sin_res, &cos_res)'; + # handle sin + $test = $str . ' puts ' . &beautify ($args[2]) . ' in sin_res'; + if ($#args == 4) { + $test .= " plus " . &beautify ($args[4]); + } + + $cline = " check_float (\"$test\", sin_res, $args[2]"; + $cline .= &new_test ($test, $args[4]); + print $file $cline; + + # handle cos + $test = $ |