diff options
Diffstat (limited to 'math/gen-auto-libm-tests.c')
-rw-r--r-- | math/gen-auto-libm-tests.c | 148 |
1 files changed, 115 insertions, 33 deletions
diff --git a/math/gen-auto-libm-tests.c b/math/gen-auto-libm-tests.c index 198d001519..eeec2ab6f0 100644 --- a/math/gen-auto-libm-tests.c +++ b/math/gen-auto-libm-tests.c @@ -210,16 +210,18 @@ typedef struct const char *name; /* The MPFR rounding mode. */ mpfr_rnd_t mpfr_mode; + /* The MPC rounding mode. */ + mpc_rnd_t mpc_mode; } rounding_mode_desc; /* List of rounding modes, in the same order as the rounding_mode enumeration. */ static const rounding_mode_desc rounding_modes[rm_num_modes] = { - { "downward", MPFR_RNDD }, - { "tonearest", MPFR_RNDN }, - { "towardzero", MPFR_RNDZ }, - { "upward", MPFR_RNDU }, + { "downward", MPFR_RNDD, MPC_RNDDD }, + { "tonearest", MPFR_RNDN, MPC_RNDNN }, + { "towardzero", MPFR_RNDZ, MPC_RNDZZ }, + { "upward", MPFR_RNDU, MPC_RNDUU }, }; /* The supported exceptions. */ @@ -394,6 +396,8 @@ typedef enum mpfr_f_f, /* MPFR function with two arguments and one result. */ mpfr_ff_f, + /* MPFR function with three arguments and one result. */ + mpfr_fff_f, /* MPFR function with a single argument and floating-point and integer results. */ mpfr_f_f1, @@ -424,6 +428,8 @@ typedef struct { int (*mpfr_f_f) (mpfr_t, const mpfr_t, mpfr_rnd_t); int (*mpfr_ff_f) (mpfr_t, const mpfr_t, const mpfr_t, mpfr_rnd_t); + int (*mpfr_fff_f) (mpfr_t, const mpfr_t, const mpfr_t, const mpfr_t, + mpfr_rnd_t); int (*mpfr_f_f1) (mpfr_t, int *, const mpfr_t, mpfr_rnd_t); int (*mpfr_if_f) (mpfr_t, long, const mpfr_t, mpfr_rnd_t); int (*mpfr_f_11) (mpfr_t, mpfr_t, const mpfr_t, mpfr_rnd_t); @@ -452,6 +458,10 @@ typedef struct /* Whether the function is a complex function, so errno setting is optional. */ bool complex_fn; + /* Whether to treat arguments given as floating-point constants as + exact only, rather than rounding them up and down to all + formats. */ + bool exact_args; /* How to calculate this function. */ func_calc_desc calc; /* The number of tests allocated for this function. */ @@ -469,26 +479,26 @@ typedef struct #define RET1(T1) 1, { T1 } #define RET2(T1, T2) 2, { T1, T2 } #define CALC(TYPE, FN) { TYPE, { .TYPE = FN } } -#define FUNC(NAME, ARGS, RET, EXACT, COMPLEX_FN, CALC) \ - { \ - NAME, ARGS, RET, EXACT, COMPLEX_FN, CALC, 0, 0, NULL \ +#define FUNC(NAME, ARGS, RET, EXACT, COMPLEX_FN, EXACT_ARGS, CALC) \ + { \ + NAME, ARGS, RET, EXACT, COMPLEX_FN, EXACT_ARGS, CALC, 0, 0, NULL \ } -#define FUNC_mpfr_f_f(NAME, MPFR_FUNC, EXACT) \ - FUNC (NAME, ARGS1 (type_fp), RET1 (type_fp), EXACT, false, \ +#define FUNC_mpfr_f_f(NAME, MPFR_FUNC, EXACT) \ + FUNC (NAME, ARGS1 (type_fp), RET1 (type_fp), EXACT, false, false, \ CALC (mpfr_f_f, MPFR_FUNC)) #define FUNC_mpfr_ff_f(NAME, MPFR_FUNC, EXACT) \ FUNC (NAME, ARGS2 (type_fp, type_fp), RET1 (type_fp), EXACT, false, \ - CALC (mpfr_ff_f, MPFR_FUNC)) + false, CALC (mpfr_ff_f, MPFR_FUNC)) #define FUNC_mpfr_if_f(NAME, MPFR_FUNC, EXACT) \ FUNC (NAME, ARGS2 (type_int, type_fp), RET1 (type_fp), EXACT, false, \ - CALC (mpfr_if_f, MPFR_FUNC)) + false, CALC (mpfr_if_f, MPFR_FUNC)) #define FUNC_mpc_c_f(NAME, MPFR_FUNC, EXACT) \ FUNC (NAME, ARGS2 (type_fp, type_fp), RET1 (type_fp), EXACT, true, \ - CALC (mpc_c_f, MPFR_FUNC)) + false, CALC (mpc_c_f, MPFR_FUNC)) #define FUNC_mpc_c_c(NAME, MPFR_FUNC, EXACT) \ FUNC (NAME, ARGS2 (type_fp, type_fp), RET2 (type_fp, type_fp), EXACT, \ - true, CALC (mpc_c_c, MPFR_FUNC)) + true, false, CALC (mpc_c_c, MPFR_FUNC)) /* List of functions handled by this program. */ static test_function test_functions[] = @@ -517,7 +527,8 @@ static test_function test_functions[] = FUNC_mpfr_f_f ("cos", mpfr_cos, false), FUNC_mpfr_f_f ("cosh", mpfr_cosh, false), FUNC ("cpow", ARGS4 (type_fp, type_fp, type_fp, type_fp), - RET2 (type_fp, type_fp), false, true, CALC (mpc_cc_c, mpc_pow)), + RET2 (type_fp, type_fp), false, true, false, + CALC (mpc_cc_c, mpc_pow)), FUNC_mpc_c_c ("csin", mpc_sin, false), FUNC_mpc_c_c ("csinh", mpc_sinh, false), FUNC_mpc_c_c ("csqrt", mpc_sqrt, false), @@ -529,12 +540,14 @@ static test_function test_functions[] = FUNC_mpfr_f_f ("exp10", mpfr_exp10, false), FUNC_mpfr_f_f ("exp2", mpfr_exp2, false), FUNC_mpfr_f_f ("expm1", mpfr_expm1, false), + FUNC ("fma", ARGS3 (type_fp, type_fp, type_fp), RET1 (type_fp), + true, false, true, CALC (mpfr_fff_f, mpfr_fma)), FUNC_mpfr_ff_f ("hypot", mpfr_hypot, false), FUNC_mpfr_f_f ("j0", mpfr_j0, false), FUNC_mpfr_f_f ("j1", mpfr_j1, false), FUNC_mpfr_if_f ("jn", mpfr_jn, false), FUNC ("lgamma", ARGS1 (type_fp), RET2 (type_fp, type_int), false, false, - CALC (mpfr_f_f1, mpfr_lgamma)), + false, CALC (mpfr_f_f1, mpfr_lgamma)), FUNC_mpfr_f_f ("log", mpfr_log, false), FUNC_mpfr_f_f ("log10", mpfr_log10, false), FUNC_mpfr_f_f ("log1p", mpfr_log1p, false), @@ -542,7 +555,7 @@ static test_function test_functions[] = FUNC_mpfr_ff_f ("pow", mpfr_pow, false), FUNC_mpfr_f_f ("sin", mpfr_sin, false), FUNC ("sincos", ARGS1 (type_fp), RET2 (type_fp, type_fp), false, false, - CALC (mpfr_f_11, mpfr_sin_cos)), + false, CALC (mpfr_f_11, mpfr_sin_cos)), FUNC_mpfr_f_f ("sinh", mpfr_sinh, false), FUNC_mpfr_f_f ("sqrt", mpfr_sqrt, true), FUNC_mpfr_f_f ("tan", mpfr_tan, false), @@ -1092,16 +1105,19 @@ round_real (mpfr_t res[rm_num_modes], /* Handle the input argument at ARG (NUL-terminated), updating the lists of test inputs in IT accordingly. NUM_PREV_ARGS arguments - are already in those lists. The argument, of type GTYPE, comes - from file FILENAME, line LINENO. */ + are already in those lists. If EXACT_ARGS, interpret a value given + as a floating-point constant exactly (it must be exact for some + supported format) rather than rounding up and down. The argument, + of type GTYPE, comes from file FILENAME, line LINENO. */ static void handle_input_arg (const char *arg, input_test *it, size_t num_prev_args, - generic_value_type gtype, + generic_value_type gtype, bool exact_args, const char *filename, unsigned int lineno) { size_t num_values = 0; generic_value values[2 * fp_num_formats]; + bool check_empty_list = false; switch (gtype) { case gtype_fp: @@ -1125,6 +1141,8 @@ handle_input_arg (const char *arg, input_test *it, size_t num_prev_args, { mpfr_t tmp; char *ep; + if (exact_args) + check_empty_list = true; mpfr_init (tmp); bool inexact = mpfr_strtofr (tmp, arg, &ep, 0, MPFR_RNDZ); if (*ep != 0 || !mpfr_number_p (tmp)) @@ -1136,7 +1154,9 @@ handle_input_arg (const char *arg, input_test *it, size_t num_prev_args, unsigned int exc_after[rm_num_modes]; round_real (rounded, exc_before, exc_after, tmp, f); mpfr_clear (tmp); - if (mpfr_number_p (rounded[rm_upward])) + if (mpfr_number_p (rounded[rm_upward]) + && (!exact_args || mpfr_equal_p (rounded[rm_upward], + rounded[rm_downward]))) { mpfr_init2 (extra_values[num_extra_values], fp_formats[f].mant_dig); @@ -1144,7 +1164,7 @@ handle_input_arg (const char *arg, input_test *it, size_t num_prev_args, rounded[rm_upward], MPFR_RNDN)); num_extra_values++; } - if (mpfr_number_p (rounded[rm_downward])) + if (mpfr_number_p (rounded[rm_downward]) && !exact_args) { mpfr_init2 (extra_values[num_extra_values], fp_formats[f].mant_dig); @@ -1195,6 +1215,10 @@ handle_input_arg (const char *arg, input_test *it, size_t num_prev_args, default: abort (); } + if (check_empty_list && num_values == 0) + error_at_line (EXIT_FAILURE, 0, filename, lineno, + "floating-point argument not exact for any format: '%s'", + arg); assert (num_values > 0 && num_values <= ARRAY_SIZE (values)); if (it->num_input_cases >= SIZE_MAX / num_values) error_at_line (EXIT_FAILURE, 0, filename, lineno, "too many input cases"); @@ -1319,7 +1343,7 @@ add_test (char *line, const char *filename, unsigned int lineno) *ep = 0; handle_input_arg (p, it, j, generic_arg_ret_type (tf->arg_types[j]), - filename, lineno); + tf->exact_args, filename, lineno); *ep = c; p = ep + 1; } @@ -1383,15 +1407,19 @@ read_input (const char *filename) } /* Calculate the generic results (round-to-zero with sticky bit) for - the function described by CALC, with inputs INPUTS. */ + the function described by CALC, with inputs INPUTS, if MODE is + rm_towardzero; for other modes, calculate results in that mode, + which must be exact zero results. */ static void calc_generic_results (generic_value *outputs, generic_value *inputs, - const func_calc_desc *calc) + const func_calc_desc *calc, rounding_mode mode) { bool inexact; int mpc_ternary; mpc_t ci1, ci2, co; + mpfr_rnd_t mode_mpfr = rounding_modes[mode].mpfr_mode; + mpc_rnd_t mode_mpc = rounding_modes[mode].mpc_mode; switch (calc->method) { @@ -1400,7 +1428,9 @@ calc_generic_results (generic_value *outputs, generic_value *inputs, outputs[0].type = gtype_fp; mpfr_init (outputs[0].value.f); inexact = calc->func.mpfr_f_f (outputs[0].value.f, inputs[0].value.f, - MPFR_RNDZ); + mode_mpfr); + if (mode != rm_towardzero) + assert (!inexact && mpfr_zero_p (outputs[0].value.f)); adjust_real (outputs[0].value.f, inexact); break; @@ -1410,7 +1440,23 @@ calc_generic_results (generic_value *outputs, generic_value *inputs, outputs[0].type = gtype_fp; mpfr_init (outputs[0].value.f); inexact = calc->func.mpfr_ff_f (outputs[0].value.f, inputs[0].value.f, - inputs[1].value.f, MPFR_RNDZ); + inputs[1].value.f, mode_mpfr); + if (mode != rm_towardzero) + assert (!inexact && mpfr_zero_p (outputs[0].value.f)); + adjust_real (outputs[0].value.f, inexact); + break; + + case mpfr_fff_f: + assert (inputs[0].type == gtype_fp); + assert (inputs[1].type == gtype_fp); + assert (inputs[2].type == gtype_fp); + outputs[0].type = gtype_fp; + mpfr_init (outputs[0].value.f); + inexact = calc->func.mpfr_fff_f (outputs[0].value.f, inputs[0].value.f, + inputs[1].value.f, inputs[2].value.f, + mode_mpfr); + if (mode != rm_towardzero) + assert (!inexact && mpfr_zero_p (outputs[0].value.f)); adjust_real (outputs[0].value.f, inexact); break; @@ -1421,7 +1467,9 @@ calc_generic_results (generic_value *outputs, generic_value *inputs, mpfr_init (outputs[0].value.f); int i = 0; inexact = calc->func.mpfr_f_f1 (outputs[0].value.f, &i, - inputs[0].value.f, MPFR_RNDZ); + inputs[0].value.f, mode_mpfr); + if (mode != rm_towardzero) + assert (!inexact && mpfr_zero_p (outputs[0].value.f)); adjust_real (outputs[0].value.f, inexact); mpz_init_set_si (outputs[1].value.i, i); break; @@ -1434,7 +1482,9 @@ calc_generic_results (generic_value *outputs, generic_value *inputs, assert (mpz_fits_slong_p (inputs[0].value.i)); long l = mpz_get_si (inputs[0].value.i); inexact = calc->func.mpfr_if_f (outputs[0].value.f, l, - inputs[1].value.f, MPFR_RNDZ); + inputs[1].value.f, mode_mpfr); + if (mode != rm_towardzero) + assert (!inexact && mpfr_zero_p (outputs[0].value.f)); adjust_real (outputs[0].value.f, inexact); break; @@ -1447,7 +1497,12 @@ calc_generic_results (generic_value *outputs, generic_value *inputs, int comb_ternary = calc->func.mpfr_f_11 (outputs[0].value.f, outputs[1].value.f, inputs[0].value.f, - MPFR_RNDZ); + mode_mpfr); + if (mode != rm_towardzero) + assert (((comb_ternary & 0x3) == 0 + && mpfr_zero_p (outputs[0].value.f)) + || ((comb_ternary & 0xc) == 0 + && mpfr_zero_p (outputs[1].value.f))); adjust_real (outputs[0].value.f, (comb_ternary & 0x3) != 0); adjust_real (outputs[1].value.f, (comb_ternary & 0xc) != 0); break; @@ -1460,7 +1515,9 @@ calc_generic_results (generic_value *outputs, generic_value *inputs, mpc_init2 (ci1, internal_precision); assert_exact (mpc_set_fr_fr (ci1, inputs[0].value.f, inputs[1].value.f, MPC_RNDNN)); - inexact = calc->func.mpc_c_f (outputs[0].value.f, ci1, MPFR_RNDZ); + inexact = calc->func.mpc_c_f (outputs[0].value.f, ci1, mode_mpfr); + if (mode != rm_towardzero) + assert (!inexact && mpfr_zero_p (outputs[0].value.f)); adjust_real (outputs[0].value.f, inexact); mpc_clear (ci1); break; @@ -1476,7 +1533,12 @@ calc_generic_results (generic_value *outputs, generic_value *inputs, mpc_init2 (co, internal_precision); assert_exact (mpc_set_fr_fr (ci1, inputs[0].value.f, inputs[1].value.f, MPC_RNDNN)); - mpc_ternary = calc->func.mpc_c_c (co, ci1, MPC_RNDZZ); + mpc_ternary = calc->func.mpc_c_c (co, ci1, mode_mpc); + if (mode != rm_towardzero) + assert ((!MPC_INEX_RE (mpc_ternary) + && mpfr_zero_p (mpc_realref (co))) + || (!MPC_INEX_IM (mpc_ternary) + && mpfr_zero_p (mpc_imagref (co)))); assert_exact (mpfr_set (outputs[0].value.f, mpc_realref (co), MPFR_RNDN)); assert_exact (mpfr_set (outputs[1].value.f, mpc_imagref (co), @@ -1503,7 +1565,12 @@ calc_generic_results (generic_value *outputs, generic_value *inputs, MPC_RNDNN)); assert_exact (mpc_set_fr_fr (ci2, inputs[2].value.f, inputs[3].value.f, MPC_RNDNN)); - mpc_ternary = calc->func.mpc_cc_c (co, ci1, ci2, MPC_RNDZZ); + mpc_ternary = calc->func.mpc_cc_c (co, ci1, ci2, mode_mpc); + if (mode != rm_towardzero) + assert ((!MPC_INEX_RE (mpc_ternary) + && mpfr_zero_p (mpc_realref (co))) + || (!MPC_INEX_IM (mpc_ternary) + && mpfr_zero_p (mpc_imagref (co)))); assert_exact (mpfr_set (outputs[0].value.f, mpc_realref (co), MPFR_RNDN)); assert_exact (mpfr_set (outputs[1].value.f, mpc_imagref (co), @@ -1674,7 +1741,7 @@ output_for_one_input_case (FILE *fp, const char *filename, test_function *tf, } } generic_value generic_outputs[MAX_NRET]; - calc_generic_results (generic_outputs, inputs, &tf->calc); + calc_generic_results (generic_outputs, inputs, &tf->calc, rm_towardzero); bool ignore_output_long32[MAX_NRET] = { false }; bool ignore_output_long64[MAX_NRET] = { false }; for (size_t i = 0; i < tf->num_ret; i++) @@ -1777,6 +1844,21 @@ output_for_one_input_case (FILE *fp, const char *filename, test_function *tf, && mpfr_cmpabs (generic_outputs[i].value.f, fp_formats[f].min) <= 0); } + /* If the result is an exact zero, the sign may + depend on the rounding mode, so recompute it + directly in that mode. */ + if (mpfr_zero_p (all_res[i][m]) + && (all_exc_before[i][m] & (1U << exc_inexact)) == 0) + { + generic_value outputs_rm[MAX_NRET]; + calc_generic_results (outputs_rm, inputs, + &tf->calc, m); + assert_exact (mpfr_set (all_res[i][m], + outputs_rm[i].value.f, + MPFR_RNDN)); + for (size_t j = 0; j < tf->num_ret; j++) + generic_value_free (&outputs_rm[j]); + } } break; |