/* Generate expected output for libm tests with MPFR and MPC.
- Copyright (C) 2013 Free Software Foundation, Inc.
+ Copyright (C) 2013-2015 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
permitted), errno is expected to be left unchanged.
The flag "no-test-inline" indicates a test is disabled for inline
- function testing; "xfail" indicates the test is disabled as
- expected to produce incorrect results, "xfail-rounding" indicates
- the test is disabled only in rounding modes other than
- round-to-nearest. Otherwise, test flags are of the form
- "spurious-<exception>" and "missing-<exception>", for any exception
- ("overflow", "underflow", "inexact", "invalid", "divbyzero"),
- "spurious-errno" and "missing-errno", to indicate when tests are
- expected to deviate from the exception and errno settings
- corresponding to the mathematical results. "xfail",
+ function testing; "ignore-zero-inf-sign" indicates the the signs of
+ zero and infinite results should be ignored; "xfail" indicates the
+ test is disabled as expected to produce incorrect results,
+ "xfail-rounding" indicates the test is disabled only in rounding
+ modes other than round-to-nearest. Otherwise, test flags are of
+ the form "spurious-<exception>" and "missing-<exception>", for any
+ exception ("overflow", "underflow", "inexact", "invalid",
+ "divbyzero"), "spurious-errno" and "missing-errno", to indicate
+ when tests are expected to deviate from the exception and errno
+ settings corresponding to the mathematical results. "xfail",
"xfail-rounding", "spurious-" and "missing-" flags should be
accompanied by a comment referring to an open bug in glibc
Bugzilla.
... : flags". rounding-mode is "tonearest", "towardzero", "upward"
or "downward". format is a name from the floating_point_formats
array, possibly followed by a sequence of ":flag" for flags from
- "long32", "long64", "before-rounding" and "after-rounding" (the
- last two indicating tests where expectations for underflow
- exceptions depend on how the architecture detects tininess).
- Inputs and outputs are specified as hex floats with the required
- suffix for the floating-point type, or plus_infty or minus_infty
- for infinite expected results, or as integer constant expressions
- (not necessarily with the right type) or IGNORE for integer inputs
- and outputs. Flags are "no-test-inline", "xfail", "<exception>",
- "<exception>-ok", "errno-<value>", "errno-<value>-ok", where
- "<exception>" and "errno-<value>" are unconditional, indicating
- that a correct result means the given exception should be raised or
- errno should be set to the given value, and other settings may be
- conditional or unconditional; "-ok" means not to test for the given
+ "long32" and "long64". Inputs and outputs are specified as hex
+ floats with the required suffix for the floating-point type, or
+ plus_infty or minus_infty for infinite expected results, or as
+ integer constant expressions (not necessarily with the right type)
+ or IGNORE for integer inputs and outputs. Flags are
+ "no-test-inline", "ignore-zero-info-sign", "xfail", "<exception>",
+ "<exception>-ok", "errno-<value>", "errno-<value>-ok", which may be
+ unconditional or conditional. "<exception>" indicates that a
+ correct result means the given exception should be raised.
+ "errno-<value>" indicates that a correct result means errno should
+ be set to the given value. "-ok" means not to test for the given
exception or errno value (whether because it was marked as possibly
missing or spurious, or because the calculation of correct results
- indicated it was optional). */
+ indicated it was optional). Conditions "before-rounding" and
+ "after-rounding" indicate tests where expectations for underflow
+ exceptions depend on how the architecture detects tininess. */
#define _GNU_SOURCE
int min_exp;
/* The largest normal value. */
mpfr_t max;
+ /* The value 0.5ulp above the least positive normal value. */
+ mpfr_t min_plus_half;
/* The least positive normal value, 2^(MIN_EXP-1). */
mpfr_t min;
/* The greatest positive subnormal value. */
enumeration. */
static fp_format_desc fp_formats[fp_num_formats] =
{
- { "flt-32", "f", NULL, 24, 128, -125, {}, {}, {}, {} },
- { "dbl-64", "", NULL, 53, 1024, -1021, {}, {}, {}, {} },
- { "ldbl-96-intel", "L", NULL, 64, 16384, -16381, {}, {}, {}, {} },
- { "ldbl-96-m68k", "L", NULL, 64, 16384, -16382, {}, {}, {}, {} },
- { "ldbl-128", "L", NULL, 113, 16384, -16381, {}, {}, {}, {} },
+ { "flt-32", "f", NULL, 24, 128, -125, {}, {}, {}, {}, {} },
+ { "dbl-64", "", NULL, 53, 1024, -1021, {}, {}, {}, {}, {} },
+ { "ldbl-96-intel", "L", NULL, 64, 16384, -16381, {}, {}, {}, {}, {} },
+ { "ldbl-96-m68k", "L", NULL, 64, 16384, -16382, {}, {}, {}, {}, {} },
+ { "ldbl-128", "L", NULL, 113, 16384, -16381, {}, {}, {}, {}, {} },
{ "ldbl-128ibm", "L", "0x1.fffffffffffff7ffffffffffff8p+1023",
- 106, 1024, -968, {}, {}, {}, {} },
+ 106, 1024, -968, {}, {}, {}, {}, {} },
};
/* The supported rounding modes. */
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. */
typedef enum
{
flag_no_test_inline,
+ flag_ignore_zero_inf_sign,
flag_xfail,
flag_xfail_rounding,
/* The "spurious" and "missing" flags must be in the same order as
static const char *const input_flags[num_input_flag_types] =
{
"no-test-inline",
+ "ignore-zero-inf-sign",
"xfail",
"xfail-rounding",
"spurious-divbyzero",
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,
/* MPFR function with integer and floating-point arguments and one
result. */
mpfr_if_f,
+ /* MPFR function with a single argument and two floating-point
+ results. */
+ mpfr_f_11,
+ /* MPC function with a single complex argument and one real
+ result. */
+ mpc_c_f,
+ /* MPC function with a single complex argument and one complex
+ result. */
+ mpc_c_c,
+ /* MPC function with two complex arguments and one complex
+ result. */
+ mpc_cc_c,
} func_calc_method;
/* Description of how to calculate a function. */
{
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);
+ int (*mpc_c_f) (mpfr_t, const mpc_t, mpfr_rnd_t);
+ int (*mpc_c_c) (mpc_t, const mpc_t, mpc_rnd_t);
+ int (*mpc_cc_c) (mpc_t, const mpc_t, const mpc_t, mpc_rnd_t);
} func;
} func_calc_desc;
/* 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. */
#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, \
+ 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, false, CALC (mpc_c_c, MPFR_FUNC))
/* List of functions handled by this program. */
static test_function test_functions[] =
FUNC_mpfr_f_f ("atan", mpfr_atan, false),
FUNC_mpfr_ff_f ("atan2", mpfr_atan2, false),
FUNC_mpfr_f_f ("atanh", mpfr_atanh, false),
+ FUNC_mpc_c_f ("cabs", mpc_abs, false),
+ FUNC_mpc_c_c ("cacos", mpc_acos, false),
+ FUNC_mpc_c_c ("cacosh", mpc_acosh, false),
+ FUNC_mpc_c_f ("carg", mpc_arg, false),
+ FUNC_mpc_c_c ("casin", mpc_asin, false),
+ FUNC_mpc_c_c ("casinh", mpc_asinh, false),
+ FUNC_mpc_c_c ("catan", mpc_atan, false),
+ FUNC_mpc_c_c ("catanh", mpc_atanh, false),
FUNC_mpfr_f_f ("cbrt", mpfr_cbrt, false),
+ FUNC_mpc_c_c ("ccos", mpc_cos, false),
+ FUNC_mpc_c_c ("ccosh", mpc_cosh, false),
+ FUNC_mpc_c_c ("cexp", mpc_exp, false),
+ FUNC_mpc_c_c ("clog", mpc_log, false),
+ FUNC_mpc_c_c ("clog10", mpc_log10, false),
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, 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),
+ FUNC_mpc_c_c ("ctan", mpc_tan, false),
+ FUNC_mpc_c_c ("ctanh", mpc_tanh, false),
FUNC_mpfr_f_f ("erf", mpfr_erf, false),
FUNC_mpfr_f_f ("erfc", mpfr_erfc, false),
FUNC_mpfr_f_f ("exp", mpfr_exp, false),
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),
FUNC_mpfr_f_f ("log2", mpfr_log2, false),
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,
+ 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),
assert_exact (mpfr_set_ui_2exp (fp_formats[f].min, 1,
fp_formats[f].min_exp - 1,
MPFR_RNDN));
+ mpfr_init2 (fp_formats[f].min_plus_half, fp_formats[f].mant_dig + 1);
+ assert_exact (mpfr_set (fp_formats[f].min_plus_half,
+ fp_formats[f].min, MPFR_RNDN));
+ mpfr_nextabove (fp_formats[f].min_plus_half);
mpfr_init2 (fp_formats[f].subnorm_max, fp_formats[f].mant_dig);
assert_exact (mpfr_set (fp_formats[f].subnorm_max, fp_formats[f].min,
MPFR_RNDN));
return 1;
}
+static size_t
+special_fill_min_subnorm_p120 (mpfr_t res0,
+ mpfr_t res1 __attribute__ ((unused)),
+ fp_format format)
+{
+ mpfr_init2 (res0, fp_formats[format].mant_dig);
+ assert_exact (mpfr_mul_2ui (res0, fp_formats[format].subnorm_min,
+ 120, MPFR_RNDN));
+ return 1;
+}
+
static size_t
special_fill_pi (mpfr_t res0, mpfr_t res1, fp_format format)
{
return 2;
}
+static size_t
+special_fill_2pi (mpfr_t res0, mpfr_t res1, fp_format format)
+{
+ mpfr_init2 (res0, fp_formats[format].mant_dig);
+ mpfr_const_pi (res0, MPFR_RNDU);
+ assert_exact (mpfr_mul_ui (res0, res0, 2, MPFR_RNDN));
+ mpfr_init2 (res1, fp_formats[format].mant_dig);
+ mpfr_const_pi (res1, MPFR_RNDD);
+ assert_exact (mpfr_mul_ui (res1, res1, 2, MPFR_RNDN));
+ return 2;
+}
+
static size_t
special_fill_e (mpfr_t res0, mpfr_t res1, fp_format format)
{
{ "-min", special_fill_minus_min },
{ "min_subnorm", special_fill_min_subnorm },
{ "-min_subnorm", special_fill_minus_min_subnorm },
+ { "min_subnorm_p120", special_fill_min_subnorm_p120 },
{ "pi", special_fill_pi },
{ "-pi", special_fill_minus_pi },
{ "pi/2", special_fill_pi_2 },
{ "-pi/6", special_fill_minus_pi_6 },
{ "pi/3", special_fill_pi_3 },
{ "2pi/3", special_fill_2pi_3 },
+ { "2pi", special_fill_2pi },
{ "e", special_fill_e },
{ "1/e", special_fill_1_e },
{ "e-1", special_fill_e_minus_1 },
mpz_t tmp;
mpz_init (tmp);
mpfr_exp_t e = mpfr_get_z_2exp (tmp, r);
- mpz_setbit (tmp, 0);
+ if (mpz_sgn (tmp) < 0)
+ {
+ mpz_neg (tmp, tmp);
+ mpz_setbit (tmp, 0);
+ mpz_neg (tmp, tmp);
+ }
+ else
+ mpz_setbit (tmp, 0);
assert_exact (mpfr_set_z_2exp (r, tmp, e, MPFR_RNDN));
mpz_clear (tmp);
}
/* 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:
{
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))
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);
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);
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");
*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;
}
}
/* 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)
{
case mpfr_f_f:
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;
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;
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;
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;
+
+ case mpfr_f_11:
+ assert (inputs[0].type == gtype_fp);
+ outputs[0].type = gtype_fp;
+ mpfr_init (outputs[0].value.f);
+ outputs[1].type = gtype_fp;
+ mpfr_init (outputs[1].value.f);
+ int comb_ternary = calc->func.mpfr_f_11 (outputs[0].value.f,
+ outputs[1].value.f,
+ inputs[0].value.f,
+ 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;
+
+ case mpc_c_f:
+ assert (inputs[0].type == gtype_fp);
+ assert (inputs[1].type == gtype_fp);
+ outputs[0].type = gtype_fp;
+ mpfr_init (outputs[0].value.f);
+ 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, 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;
+
+ case mpc_c_c:
+ assert (inputs[0].type == gtype_fp);
+ assert (inputs[1].type == gtype_fp);
+ outputs[0].type = gtype_fp;
+ mpfr_init (outputs[0].value.f);
+ outputs[1].type = gtype_fp;
+ mpfr_init (outputs[1].value.f);
+ mpc_init2 (ci1, internal_precision);
+ 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, 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),
+ MPFR_RNDN));
+ adjust_real (outputs[0].value.f, MPC_INEX_RE (mpc_ternary));
+ adjust_real (outputs[1].value.f, MPC_INEX_IM (mpc_ternary));
+ mpc_clear (ci1);
+ mpc_clear (co);
+ break;
+
+ case mpc_cc_c:
+ assert (inputs[0].type == gtype_fp);
+ assert (inputs[1].type == gtype_fp);
+ assert (inputs[2].type == gtype_fp);
+ assert (inputs[3].type == gtype_fp);
+ outputs[0].type = gtype_fp;
+ mpfr_init (outputs[0].value.f);
+ outputs[1].type = gtype_fp;
+ mpfr_init (outputs[1].value.f);
+ mpc_init2 (ci1, internal_precision);
+ mpc_init2 (ci2, internal_precision);
+ mpc_init2 (co, internal_precision);
+ assert_exact (mpc_set_fr_fr (ci1, inputs[0].value.f, inputs[1].value.f,
+ 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, 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),
+ MPFR_RNDN));
+ adjust_real (outputs[0].value.f, MPC_INEX_RE (mpc_ternary));
+ adjust_real (outputs[1].value.f, MPC_INEX_IM (mpc_ternary));
+ mpc_clear (ci1);
+ mpc_clear (ci2);
+ mpc_clear (co);
break;
default:
}
}
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++)
<= 0));
may_underflow
|= (!mpfr_zero_p (generic_outputs[i].value.f)
- && mpfr_cmpabs (generic_outputs[i].value.f,
- fp_formats[f].min) <= 0);
+ && (mpfr_cmpabs (generic_outputs[i].value.f,
+ fp_formats[f].min_plus_half)
+ <= 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;
{
bool before_after_matters
= tf->exact && merged_exc_before[m] != merged_exc_after[m];
- for (int after = 0; after <= 1; after++)
+ if (before_after_matters)
{
- if (after == 1 && !before_after_matters)
- continue;
- const char *after_cond;
- if (before_after_matters)
- after_cond = (after
- ? ":after-rounding"
- : ":before-rounding");
- else
- after_cond = "";
- unsigned int merged_exc = (after
- ? merged_exc_after[m]
- : merged_exc_before[m]);
- if (fprintf (fp, "= %s %s %s%s%s", tf->name,
- rounding_modes[m].name, fp_formats[f].name,
- long_cond, after_cond) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'", filename);
- /* Print inputs. */
- for (size_t i = 0; i < tf->num_args; i++)
- output_generic_value (fp, filename, &inputs[i], false,
- tf->arg_types[i], f, long_bits);
- if (fputs (" :", fp) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'", filename);
- /* Print outputs. */
- bool must_erange = false;
- for (size_t i = 0; i < tf->num_ret; i++)
+ assert ((merged_exc_before[m] ^ merged_exc_after[m])
+ == (1U << exc_underflow));
+ assert ((merged_exc_before[m] & (1U << exc_underflow)) != 0);
+ }
+ unsigned int merged_exc = merged_exc_before[m];
+ if (fprintf (fp, "= %s %s %s%s", tf->name,
+ rounding_modes[m].name, fp_formats[f].name,
+ long_cond) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'", filename);
+ /* Print inputs. */
+ for (size_t i = 0; i < tf->num_args; i++)
+ output_generic_value (fp, filename, &inputs[i], false,
+ tf->arg_types[i], f, long_bits);
+ if (fputs (" :", fp) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'", filename);
+ /* Print outputs. */
+ bool must_erange = false;
+ for (size_t i = 0; i < tf->num_ret; i++)
+ {
+ generic_value g;
+ g.type = generic_outputs[i].type;
+ switch (g.type)
{
- generic_value g;
- g.type = generic_outputs[i].type;
- switch (g.type)
- {
- case gtype_fp:
- if (mpfr_inf_p (all_res[i][m])
- && (all_exc_before[i][m]
- & (1U << exc_overflow)) != 0)
- must_erange = true;
- if (mpfr_zero_p (all_res[i][m])
- && (tf->exact
- || mpfr_zero_p (all_res[i][rm_tonearest]))
- && (all_exc_before[i][m]
- & (1U << exc_underflow)) != 0)
- must_erange = true;
- mpfr_init2 (g.value.f, fp_formats[f].mant_dig);
- assert_exact (mpfr_set (g.value.f, all_res[i][m],
- MPFR_RNDN));
- break;
+ case gtype_fp:
+ if (mpfr_inf_p (all_res[i][m])
+ && (all_exc_before[i][m]
+ & (1U << exc_overflow)) != 0)
+ must_erange = true;
+ if (mpfr_zero_p (all_res[i][m])
+ && (tf->exact
+ || mpfr_zero_p (all_res[i][rm_tonearest]))
+ && (all_exc_before[i][m]
+ & (1U << exc_underflow)) != 0)
+ must_erange = true;
+ mpfr_init2 (g.value.f, fp_formats[f].mant_dig);
+ assert_exact (mpfr_set (g.value.f, all_res[i][m],
+ MPFR_RNDN));
+ break;
- case gtype_int:
- mpz_init (g.value.i);
- mpz_set (g.value.i, generic_outputs[i].value.i);
- break;
+ case gtype_int:
+ mpz_init (g.value.i);
+ mpz_set (g.value.i, generic_outputs[i].value.i);
+ break;
- default:
- abort ();
- }
- output_generic_value (fp, filename, &g, ignore_output[i],
- tf->ret_types[i], f, long_bits);
- generic_value_free (&g);
+ default:
+ abort ();
}
- if (fputs (" :", fp) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'", filename);
- /* Print miscellaneous flags (passed through from
- input). */
- for (size_t i = 0; i < it->num_flags; i++)
- switch (it->flags[i].type)
- {
- case flag_no_test_inline:
- case flag_xfail:
- if (fprintf (fp, " %s%s",
- input_flags[it->flags[i].type],
- (it->flags[i].cond
- ? it->flags[i].cond
- : "")) < 0)
+ output_generic_value (fp, filename, &g, ignore_output[i],
+ tf->ret_types[i], f, long_bits);
+ generic_value_free (&g);
+ }
+ if (fputs (" :", fp) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'", filename);
+ /* Print miscellaneous flags (passed through from
+ input). */
+ for (size_t i = 0; i < it->num_flags; i++)
+ switch (it->flags[i].type)
+ {
+ case flag_no_test_inline:
+ case flag_ignore_zero_inf_sign:
+ case flag_xfail:
+ if (fprintf (fp, " %s%s",
+ input_flags[it->flags[i].type],
+ (it->flags[i].cond
+ ? it->flags[i].cond
+ : "")) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'",
+ filename);
+ break;
+ case flag_xfail_rounding:
+ if (m != rm_tonearest)
+ if (fprintf (fp, " xfail%s",
+ (it->flags[i].cond
+ ? it->flags[i].cond
+ : "")) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'",
+ filename);
+ break;
+ default:
+ break;
+ }
+ /* Print exception flags and compute errno
+ expectations where not already computed. */
+ bool may_edom = false;
+ bool must_edom = false;
+ bool may_erange = must_erange || may_underflow;
+ for (fp_exception e = exc_first_exception;
+ e < exc_num_exceptions;
+ e++)
+ {
+ bool expect_e = (merged_exc & (1U << e)) != 0;
+ bool e_optional = false;
+ switch (e)
+ {
+ case exc_divbyzero:
+ if (expect_e)
+ may_erange = must_erange = true;
+ break;
+
+ case exc_inexact:
+ if (!tf->exact)
+ e_optional = true;
+ break;
+
+ case exc_invalid:
+ if (expect_e)
+ may_edom = must_edom = true;
+ break;
+
+ case exc_overflow:
+ if (expect_e)
+ may_erange = true;
+ break;
+
+ case exc_underflow:
+ if (expect_e)
+ may_erange = true;
+ if (must_underflow)
+ assert (expect_e);
+ if (may_underflow && !must_underflow)
+ e_optional = true;
+ break;
+
+ default:
+ abort ();
+ }
+ if (e_optional)
+ {
+ assert (!before_after_matters);
+ if (fprintf (fp, " %s-ok", exceptions[e]) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'",
+ filename);
+ }
+ else
+ {
+ if (expect_e)
+ if (fprintf (fp, " %s", exceptions[e]) < 0)
error (EXIT_FAILURE, errno, "write to '%s'",
filename);
- break;
- case flag_xfail_rounding:
- if (m != rm_tonearest)
- if (fprintf (fp, " xfail%s",
- (it->flags[i].cond
- ? it->flags[i].cond
- : "")) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'",
- filename);
- break;
- default:
- break;
- }
- /* Print exception flags and compute errno
- expectations where not already computed. */
- bool may_edom = false;
- bool must_edom = false;
- bool may_erange = must_erange || may_underflow;
- for (fp_exception e = exc_first_exception;
- e < exc_num_exceptions;
- e++)
- {
- bool expect_e = (merged_exc & (1U << e)) != 0;
- bool e_optional = false;
- switch (e)
- {
- case exc_divbyzero:
- if (expect_e)
- may_erange = must_erange = true;
- break;
-
- case exc_inexact:
- if (!tf->exact)
- e_optional = true;
- break;
-
- case exc_invalid:
- if (expect_e)
- may_edom = must_edom = true;
- break;
-
- case exc_overflow:
- if (expect_e)
- may_erange = true;
- break;
-
- case exc_underflow:
- if (expect_e)
- may_erange = true;
- if (must_underflow)
- assert (expect_e);
- if (may_underflow && !must_underflow)
- e_optional = true;
- break;
-
- default:
- abort ();
- }
- if (e_optional)
- {
- if (fprintf (fp, " %s-ok", exceptions[e]) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'",
- filename);
- }
- else
+ if (before_after_matters && e == exc_underflow)
+ if (fputs (":before-rounding", fp) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'",
+ filename);
+ for (int after = 0; after <= 1; after++)
{
- if (expect_e)
- if (fprintf (fp, " %s", exceptions[e]) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'",
- filename);
+ bool expect_e_here = expect_e;
+ if (after == 1 && (!before_after_matters
+ || e != exc_underflow))
+ continue;
+ const char *after_cond;
+ if (before_after_matters && e == exc_underflow)
+ {
+ after_cond = (after
+ ? ":after-rounding"
+ : ":before-rounding");
+ expect_e_here = !after;
+ }
+ else
+ after_cond = "";
input_flag_type okflag;
- okflag = (expect_e
+ okflag = (expect_e_here
? flag_missing_first
: flag_spurious_first) + e;
for (size_t i = 0; i < it->num_flags; i++)
if (it->flags[i].type == okflag)
- if (fprintf (fp, " %s-ok%s",
+ if (fprintf (fp, " %s-ok%s%s",
exceptions[e],
(it->flags[i].cond
? it->flags[i].cond
- : "")) < 0)
+ : ""), after_cond) < 0)
error (EXIT_FAILURE, errno, "write to '%s'",
filename);
}
}
- /* Print errno expectations. */
- if (tf->complex_fn)
- {
- must_edom = false;
- must_erange = false;
- }
- if (may_edom && !must_edom)
- {
- if (fputs (" errno-edom-ok", fp) < 0)
+ }
+ /* Print errno expectations. */
+ if (tf->complex_fn)
+ {
+ must_edom = false;
+ must_erange = false;
+ }
+ if (may_edom && !must_edom)
+ {
+ if (fputs (" errno-edom-ok", fp) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'",
+ filename);
+ }
+ else
+ {
+ if (must_edom)
+ if (fputs (" errno-edom", fp) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'",
+ filename);
+ input_flag_type okflag = (must_edom
+ ? flag_missing_errno
+ : flag_spurious_errno);
+ for (size_t i = 0; i < it->num_flags; i++)
+ if (it->flags[i].type == okflag)
+ if (fprintf (fp, " errno-edom-ok%s",
+ (it->flags[i].cond
+ ? it->flags[i].cond
+ : "")) < 0)
error (EXIT_FAILURE, errno, "write to '%s'",
filename);
- }
- else
- {
- if (must_edom)
- if (fputs (" errno-edom", fp) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'",
- filename);
- input_flag_type okflag = (must_edom
- ? flag_missing_errno
- : flag_spurious_errno);
- for (size_t i = 0; i < it->num_flags; i++)
- if (it->flags[i].type == okflag)
- if (fprintf (fp, " errno-edom-ok%s",
- (it->flags[i].cond
- ? it->flags[i].cond
- : "")) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'",
- filename);
- }
- if (may_erange && !must_erange)
- {
- if (fputs (" errno-erange-ok", fp) < 0)
+ }
+ if (before_after_matters)
+ assert (may_erange && !must_erange);
+ if (may_erange && !must_erange)
+ {
+ if (fprintf (fp, " errno-erange-ok%s",
+ (before_after_matters
+ ? ":before-rounding"
+ : "")) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'",
+ filename);
+ }
+ if (before_after_matters || !(may_erange && !must_erange))
+ {
+ if (must_erange)
+ if (fputs (" errno-erange", fp) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'",
+ filename);
+ input_flag_type okflag = (must_erange
+ ? flag_missing_errno
+ : flag_spurious_errno);
+ for (size_t i = 0; i < it->num_flags; i++)
+ if (it->flags[i].type == okflag)
+ if (fprintf (fp, " errno-erange-ok%s%s",
+ (it->flags[i].cond
+ ? it->flags[i].cond
+ : ""),
+ (before_after_matters
+ ? ":after-rounding"
+ : "")) < 0)
error (EXIT_FAILURE, errno, "write to '%s'",
filename);
- }
- else
- {
- if (must_erange)
- if (fputs (" errno-erange", fp) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'",
- filename);
- input_flag_type okflag = (must_erange
- ? flag_missing_errno
- : flag_spurious_errno);
- for (size_t i = 0; i < it->num_flags; i++)
- if (it->flags[i].type == okflag)
- if (fprintf (fp, " errno-erange-ok%s",
- (it->flags[i].cond
- ? it->flags[i].cond
- : "")) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'",
- filename);
- }
- if (putc ('\n', fp) < 0)
- error (EXIT_FAILURE, errno, "write to '%s'", filename);
}
+ if (putc ('\n', fp) < 0)
+ error (EXIT_FAILURE, errno, "write to '%s'", filename);
}
for (size_t i = 0; i < tf->num_ret; i++)
{