Commit 9f32d037 by Tobias Schlüter Committed by Tobias Schlüter

simplify.c (gfc_simplify_nearest): Overhaul.

fortran/
* simplify.c (gfc_simplify_nearest): Overhaul.

testsuite/
* gfortran.dg/fold_nearest.f90: New test.

From-SVN: r97987
parent 0d667716
2005-04-11 Tobias Schl"uter <tobias.schlueter@physik.uni-muenchen.de>
* simplify.c (gfc_simplify_nearest): Overhaul.
2005-04-10 Kazu Hirata <kazu@cs.umass.edu> 2005-04-10 Kazu Hirata <kazu@cs.umass.edu>
* interface.c: Fix a comment typo. * interface.c: Fix a comment typo.
......
...@@ -2263,64 +2263,82 @@ gfc_expr * ...@@ -2263,64 +2263,82 @@ gfc_expr *
gfc_simplify_nearest (gfc_expr * x, gfc_expr * s) gfc_simplify_nearest (gfc_expr * x, gfc_expr * s)
{ {
gfc_expr *result; gfc_expr *result;
float rval; mpfr_t tmp;
double val, eps; int direction, sgn;
int p, i, k, match_float;
/* FIXME: This implementation is dopey and probably not quite right,
but it's a start. */
if (x->expr_type != EXPR_CONSTANT) if (x->expr_type != EXPR_CONSTANT || s->expr_type != EXPR_CONSTANT)
return NULL; return NULL;
k = gfc_validate_kind (x->ts.type, x->ts.kind, false); gfc_set_model_kind (x->ts.kind);
result = gfc_copy_expr (x);
result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where);
val = mpfr_get_d (x->value.real, GFC_RND_MODE); direction = mpfr_sgn (s->value.real);
p = gfc_real_kinds[k].digits;
eps = 1.; if (direction == 0)
for (i = 1; i < p; ++i)
{ {
eps = eps / 2.; gfc_error ("Second argument of NEAREST at %L may not be zero",
&s->where);
gfc_free (result);
return &gfc_bad_expr;
} }
/* TODO we should make sure that 'float' matches kind 4 */ /* TODO: Use mpfr_nextabove and mpfr_nextbelow once we move to a
match_float = gfc_real_kinds[k].kind == 4; newer version of mpfr. */
if (mpfr_cmp_ui (s->value.real, 0) > 0)
{ sgn = mpfr_sgn (x->value.real);
if (match_float)
if (sgn == 0)
{ {
rval = (float) val; int k = gfc_validate_kind (BT_REAL, x->ts.kind, 0);
rval = rval + eps;
mpfr_set_d (result->value.real, rval, GFC_RND_MODE); if (direction > 0)
} mpfr_add (result->value.real,
x->value.real, gfc_real_kinds[k].tiny, GFC_RND_MODE);
else else
{ mpfr_sub (result->value.real,
val = val + eps; x->value.real, gfc_real_kinds[k].tiny, GFC_RND_MODE);
mpfr_set_d (result->value.real, val, GFC_RND_MODE);
} #if 0
/* FIXME: This gives an arithmetic error because we compare
against tiny when range-checking. Also, it doesn't give the
right value. */
/* TINY is the smallest model number, we want the smallest
machine representable number. Therefore we have to shift the
value to the right by the number of digits - 1. */
mpfr_div_2ui (result->value.real, result->value.real,
gfc_real_kinds[k].precision - 1, GFC_RND_MODE);
#endif
} }
else if (mpfr_cmp_ui (s->value.real, 0) < 0) else
{ {
if (match_float) if (sgn < 0)
{ {
rval = (float) val; direction = -direction;
rval = rval - eps; mpfr_neg (result->value.real, result->value.real, GFC_RND_MODE);
mpfr_set_d (result->value.real, rval, GFC_RND_MODE);
} }
if (direction > 0)
mpfr_add_one_ulp (result->value.real, GFC_RND_MODE);
else else
{ {
val = val - eps; /* In this case the exponent can shrink, which makes us skip
mpfr_set_d (result->value.real, val, GFC_RND_MODE); over one number because we substract one ulp with the
} larger exponent. Thus we need to compensate for this. */
mpfr_init_set (tmp, result->value.real, GFC_RND_MODE);
mpfr_sub_one_ulp (result->value.real, GFC_RND_MODE);
mpfr_add_one_ulp (result->value.real, GFC_RND_MODE);
/* If we're back to where we started, the spacing is one
ulp, and we get the correct result by subtracting. */
if (mpfr_cmp (tmp, result->value.real) == 0)
mpfr_sub_one_ulp (result->value.real, GFC_RND_MODE);
mpfr_clear (tmp);
} }
else
{ if (sgn < 0)
gfc_error ("Invalid second argument of NEAREST at %L", &s->where); mpfr_neg (result->value.real, result->value.real, GFC_RND_MODE);
gfc_free (result);
return &gfc_bad_expr;
} }
return range_check (result, "NEAREST"); return range_check (result, "NEAREST");
......
2005-04-11 Tobias Schl"uter <tobias.schlueter@physik.uni-muenchen.de>
* gfortran.dg/fold_nearest.f90: New test.
2005-04-11 Andrew Pinski <pinskia@physics.uc.edu> 2005-04-11 Andrew Pinski <pinskia@physics.uc.edu>
* gcc.dg/tree-ssa/alias-1.c: New test. * gcc.dg/tree-ssa/alias-1.c: New test.
......
! { dg-do run }
! Tests for the constant folding of the NEAREST intrinsic
! We compare against the results of the runtime implementation,
! thereby making sure that they remain consistent
REAL, PARAMETER :: x(10) = (/ 1., 0.49999997, 0.5, 8388609.0, -1., &
-0.49999997, -0.5, -8388609.0, &
0., 0. /), &
dir(10) = (/ -1., +1., -1., -1., +1., &
-1., +1., +1., &
+1.,-1./)
REAL :: a(10)
a = x
if (nearest (x(1), dir(1)) /= nearest (a(1), dir(1))) call abort ()
if (nearest (x(2), dir(2)) /= nearest (a(2), dir(2))) call abort ()
if (nearest (x(3), dir(3)) /= nearest (a(3), dir(3))) call abort ()
if (nearest (x(4), dir(4)) /= nearest (a(4), dir(4))) call abort ()
if (nearest (x(5), dir(5)) /= nearest (a(5), dir(5))) call abort ()
if (nearest (x(6), dir(6)) /= nearest (a(6), dir(6))) call abort ()
if (nearest (x(7), dir(7)) /= nearest (a(7), dir(7))) call abort ()
if (nearest (x(8), dir(8)) /= nearest (a(8), dir(8))) call abort ()
! These last two tests are commented out because mpfr provides no support
! for denormals, and therefore we get TINY instead of the correct result.
!if (nearest (x(9), dir(9)) /= nearest (a(9), dir(9))) call abort ()
!if (nearest (x(10), dir(10)) /= nearest (a(10), dir(10))) call abort ()
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment