diff options
Diffstat (limited to 'math')
-rw-r--r-- | math/Makefile | 2 | ||||
-rw-r--r-- | math/Versions | 1 | ||||
-rw-r--r-- | math/bits/mathcalls.h | 3 | ||||
-rw-r--r-- | math/libm-test.inc | 155 | ||||
-rw-r--r-- | math/s_canonicalize_template.c | 37 |
5 files changed, 185 insertions, 13 deletions
diff --git a/math/Makefile b/math/Makefile index 7cecba5357..f400d7b741 100644 --- a/math/Makefile +++ b/math/Makefile @@ -51,7 +51,7 @@ gen-libm-calls = cargF conjF cimagF crealF cabsF s_cacosF \ k_casinhF s_csinhF k_casinhF s_csinhF s_catanhF s_catanF \ s_ctanF s_ctanhF s_cexpF s_clogF s_cprojF s_csqrtF \ s_cpowF s_clog10F s_fdimF s_nextdownF s_fmaxF s_fminF \ - s_nanF s_iseqsigF + s_nanF s_iseqsigF s_canonicalizeF libm-calls = \ e_acosF e_acoshF e_asinF e_atan2F e_atanhF e_coshF e_expF e_fmodF \ diff --git a/math/Versions b/math/Versions index a2e0d900ad..0cd594b378 100644 --- a/math/Versions +++ b/math/Versions @@ -220,5 +220,6 @@ libm { totalorder; totalorderf; totalorderl; totalordermag; totalordermagf; totalordermagl; getpayload; getpayloadf; getpayloadl; + canonicalize; canonicalizef; canonicalizel; } } diff --git a/math/bits/mathcalls.h b/math/bits/mathcalls.h index c5853a325f..2fd1d289da 100644 --- a/math/bits/mathcalls.h +++ b/math/bits/mathcalls.h @@ -395,6 +395,9 @@ __MATHDECL_1 (int, totalorder,, (_Mdouble_ __x, _Mdouble_ __y)) __MATHDECL_1 (int, totalordermag,, (_Mdouble_ __x, _Mdouble_ __y)) __attribute__ ((__const__)); +/* Canonicalize floating-point representation. */ +__MATHDECL_1 (int, canonicalize,, (_Mdouble_ *__cx, const _Mdouble_ *__x)); + /* Get NaN payload. */ __MATHCALL (getpayload,, (const _Mdouble_ *__x)); #endif diff --git a/math/libm-test.inc b/math/libm-test.inc index 89e0e59638..710633842c 100644 --- a/math/libm-test.inc +++ b/math/libm-test.inc @@ -43,7 +43,8 @@ /* This testsuite has currently tests for: acos, acosh, asin, asinh, atan, atan2, atanh, - cbrt, ceil, copysign, cos, cosh, drem, erf, erfc, exp, exp10, exp2, expm1, + canonicalize, cbrt, ceil, copysign, cos, cosh, drem, + erf, erfc, exp, exp10, exp2, expm1, fabs, fdim, finite, floor, fma, fmax, fmin, fmod, fpclassify, frexp, gamma, getpayload, hypot, ilogb, iscanonical, isfinite, isinf, isnan, isnormal, issignaling, @@ -85,8 +86,9 @@ against. These implemented tests should check all cases that are specified in ISO C99. - NaN values: The payload of NaNs is not examined, but is set in - inputs for functions where it is significant. + NaN values: The payload of NaNs is set in inputs for functions + where it is significant, and is examined in the outputs of some + functions. Inline functions: Inlining functions should give an improvement in speed - but not in precission. The inlined functions return @@ -172,17 +174,22 @@ /* Some special test flags, passed together with exceptions. */ #define IGNORE_ZERO_INF_SIGN 0x400 #define TEST_NAN_SIGN 0x800 -#define NO_TEST_INLINE 0x1000 -#define XFAIL_TEST 0x2000 +#define TEST_NAN_PAYLOAD 0x1000 +#define NO_TEST_INLINE 0x2000 +#define XFAIL_TEST 0x4000 /* Indicate errno settings required or disallowed. */ -#define ERRNO_UNCHANGED 0x4000 -#define ERRNO_EDOM 0x8000 -#define ERRNO_ERANGE 0x10000 +#define ERRNO_UNCHANGED 0x8000 +#define ERRNO_EDOM 0x10000 +#define ERRNO_ERANGE 0x20000 /* Flags generated by gen-libm-test.pl, not entered here manually. */ -#define IGNORE_RESULT 0x20000 -#define NON_FINITE 0x40000 -#define TEST_SNAN 0x80000 -#define NO_TEST_MATHVEC 0x100000 +#define IGNORE_RESULT 0x40000 +#define NON_FINITE 0x80000 +#define TEST_SNAN 0x100000 +#define NO_TEST_MATHVEC 0x200000 + +#define TEST_NAN_PAYLOAD_CANONICALIZE (SNAN_TESTS_PRESERVE_PAYLOAD \ + ? TEST_NAN_PAYLOAD \ + : 0) #define __CONCATX(a,b) __CONCAT(a,b) @@ -801,6 +808,13 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected, ok = 0; printf ("signaling NaN has wrong sign.\n"); } + else if ((exceptions & TEST_NAN_PAYLOAD) != 0 + && (FUNC (getpayload) (&computed) + != FUNC (getpayload) (&expected))) + { + ok = 0; + printf ("signaling NaN has wrong payload.\n"); + } else ok = 1; } @@ -814,6 +828,13 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected, ok = 0; printf ("quiet NaN has wrong sign.\n"); } + else if ((exceptions & TEST_NAN_PAYLOAD) != 0 + && (FUNC (getpayload) (&computed) + != FUNC (getpayload) (&expected))) + { + ok = 0; + printf ("quiet NaN has wrong payload.\n"); + } else ok = 1; } @@ -1277,6 +1298,18 @@ struct test_fFF_11_data FLOAT extra2_expected; } rd, rn, rz, ru; }; +struct test_Ffp_b1_data +{ + const char *arg_str; + FLOAT arg; + struct + { + int expected; + int exceptions; + int extra_test; + FLOAT extra_expected; + } rd, rn, rz, ru; +}; /* Set the rounding mode, or restore the saved value. */ #define IF_ROUND_INIT_ /* Empty. */ @@ -1550,6 +1583,36 @@ struct test_fFF_11_data (ARRAY)[i].RM_##ROUNDING_MODE.extra_test, \ (ARRAY)[i].RM_##ROUNDING_MODE.extra_expected); \ ROUND_RESTORE_ ## ROUNDING_MODE +#define RUN_TEST_Ffp_b1(ARG_STR, FUNC_NAME, ARG, EXPECTED, \ + EXCEPTIONS, EXTRA_VAR, EXTRA_TEST, \ + EXTRA_EXPECTED) \ + do \ + if (enable_test (EXCEPTIONS)) \ + { \ + COMMON_TEST_SETUP (ARG_STR); \ + (EXTRA_VAR) = (EXTRA_EXPECTED) == 0 ? 1 : 0; \ + check_bool (test_name, FUNC_TEST (FUNC_NAME) (&(EXTRA_VAR), \ + &(ARG)), \ + EXPECTED, EXCEPTIONS); \ + EXTRA_OUTPUT_TEST_SETUP (ARG_STR, 1); \ + if (EXTRA_TEST) \ + check_float (extra1_name, EXTRA_VAR, EXTRA_EXPECTED, \ + (EXCEPTIONS) & TEST_NAN_PAYLOAD); \ + EXTRA_OUTPUT_TEST_CLEANUP (1); \ + COMMON_TEST_CLEANUP; \ + } \ + while (0) +#define RUN_TEST_LOOP_Ffp_b1(FUNC_NAME, ARRAY, ROUNDING_MODE, \ + EXTRA_VAR) \ + IF_ROUND_INIT_ ## ROUNDING_MODE \ + for (size_t i = 0; i < sizeof (ARRAY) / sizeof (ARRAY)[0]; i++) \ + RUN_TEST_Ffp_b1 ((ARRAY)[i].arg_str, FUNC_NAME, (ARRAY)[i].arg, \ + (ARRAY)[i].RM_##ROUNDING_MODE.expected, \ + (ARRAY)[i].RM_##ROUNDING_MODE.exceptions, \ + EXTRA_VAR, \ + (ARRAY)[i].RM_##ROUNDING_MODE.extra_test, \ + (ARRAY)[i].RM_##ROUNDING_MODE.extra_expected); \ + ROUND_RESTORE_ ## ROUNDING_MODE #define RUN_TEST_c_c(ARG_STR, FUNC_NAME, ARGR, ARGC, EXPR, EXPC, \ EXCEPTIONS) \ do \ @@ -3557,6 +3620,71 @@ cacosh_test (void) } +static const struct test_Ffp_b1_data canonicalize_test_data[] = + { + TEST_Ffp_b1 (canonicalize, plus_infty, 0, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, minus_infty, 0, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, plus_zero, 0, plus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, minus_zero, 0, minus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, 1000, 0, 1000, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, max_value, 0, max_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, -max_value, 0, -max_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, min_value, 0, min_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, -min_value, 0, -min_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, min_subnorm_value, 0, min_subnorm_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, -min_subnorm_value, 0, -min_subnorm_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_Ffp_b1 (canonicalize, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, -qnan_value, 0, -qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, snan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN), + TEST_Ffp_b1 (canonicalize, -snan_value, 0, -qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN), +#if HIGH_ORDER_BIT_IS_SET_FOR_SNAN + TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x0"), 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN), + TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x0"), 0, -qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN), +#else + TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x0"), 0, qnan_value_pl ("0x0"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x0"), 0, -qnan_value_pl ("0x0"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), +#endif + TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x1"), 0, qnan_value_pl ("0x1"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x1"), 0, -qnan_value_pl ("0x1"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x1"), 0, qnan_value_pl ("0x1"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), + TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x1"), 0, -qnan_value_pl ("0x1"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), + TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x2"), 0, qnan_value_pl ("0x2"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x2"), 0, -qnan_value_pl ("0x2"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x2"), 0, qnan_value_pl ("0x2"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), + TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x2"), 0, -qnan_value_pl ("0x2"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), + TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x3fffff"), 0, qnan_value_pl ("0x3fffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x3fffff"), 0, -qnan_value_pl ("0x3fffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x3fffff"), 0, qnan_value_pl ("0x3fffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), + TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x3fffff"), 0, -qnan_value_pl ("0x3fffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), +#if PAYLOAD_DIG >= 51 + TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x7ffffffffffff"), 0, qnan_value_pl ("0x7ffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x7ffffffffffff"), 0, -qnan_value_pl ("0x7ffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x7ffffffffffff"), 0, qnan_value_pl ("0x7ffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), + TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x7ffffffffffff"), 0, -qnan_value_pl ("0x7ffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), +#endif +#if PAYLOAD_DIG >= 62 + TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x3fffffffffffffff"), 0, qnan_value_pl ("0x3fffffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x3fffffffffffffff"), 0, -qnan_value_pl ("0x3fffffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x3fffffffffffffff"), 0, qnan_value_pl ("0x3fffffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), + TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x3fffffffffffffff"), 0, -qnan_value_pl ("0x3fffffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), +#endif +#if PAYLOAD_DIG >= 111 + TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x7fffffffffffffffffffffffffff"), 0, qnan_value_pl ("0x7fffffffffffffffffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x7fffffffffffffffffffffffffff"), 0, -qnan_value_pl ("0x7fffffffffffffffffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD), + TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x7fffffffffffffffffffffffffff"), 0, qnan_value_pl ("0x7fffffffffffffffffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), + TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x7fffffffffffffffffffffffffff"), 0, -qnan_value_pl ("0x7fffffffffffffffffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE), +#endif + }; + +static void +canonicalize_test (void) +{ + FLOAT x; + + ALL_RM_TEST (canonicalize, 1, canonicalize_test_data, RUN_TEST_LOOP_Ffp_b1, END, x); +} + + static const struct test_c_f_data carg_test_data[] = { /* carg (x + iy) is specified as atan2 (y, x) */ @@ -13511,6 +13639,9 @@ main (int argc, char **argv) totalorder_test (); totalordermag_test (); + /* Canonicalize functions: */ + canonicalize_test (); + /* NaN functions: */ getpayload_test (); diff --git a/math/s_canonicalize_template.c b/math/s_canonicalize_template.c new file mode 100644 index 0000000000..fa06f5c083 --- /dev/null +++ b/math/s_canonicalize_template.c @@ -0,0 +1,37 @@ +/* Canonicalize floating-point representation. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + 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/>. */ + +#include <math.h> + +int +M_DECL_FUNC (__canonicalize) (FLOAT *cx, const FLOAT *x) +{ + FLOAT val = *x; + /* For all binary formats supported by glibc, iscanonical only fails + if the representation is not a valid representation of the type, + so the only work to do is for signaling NaNs. */ + if (!iscanonical (val)) + return 1; + if (issignaling (val)) + *cx = val + val; + else + *cx = val; + return 0; +} + +declare_mgen_alias (__canonicalize, canonicalize) |