This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH/gfortran] Fix rounding in constant folding


Tobias Schlüter wrote:
> gives the following output:
>   0.5000000               1
>   0.4999999               0
>   0.5000000               0
> So the result for NEAREST as evaluated by the constant folders is too small.
> It looks like mpfr provides what is needed, so I'll cook up a patch.

Unfortunately, I couldn't get it to work, neither with mpfr_{add|sub}_one_ulp,
nor with the hand-written equivalent (?) below.  The following testcase
   print *, 0.49999997, 0.49999997 < 0.5, nint (0.49999997)
   print *, nearest (0.5, -1.), nearest (0.5, -1.) < 0.5, &
        nint(nearest (0.5, -1.))
   x = 0.5
   print *, nearest (x, -1.), nearest (x, -1.) < 0.5, &
        nint(nearest(x, -1.))
   end
produces this result with both approaches:
   [tobi@marktplatz tests]$ ./a.out
     0.5000000     T           1
     0.4999999     T           0
     0.5000000     T           0
   [tobi@marktplatz tests]$
the second to last line should match the last line, so something's wrong here.

I'm going to bed now, maybe I'll see clearer tomorrow.  Is there something
obviously wrong?

- Tobi

ps I know that I'm introducing a memory leak, this is by no means meant for
inclusion.

Index: simplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/simplify.c,v
retrieving revision 1.21
diff -c -3 -p -r1.21 simplify.c
*** simplify.c  7 Apr 2005 18:26:37 -0000       1.21
--- simplify.c  9 Apr 2005 23:38:18 -0000
*************** gfc_expr *
*** 2311,2372 ****
  gfc_simplify_nearest (gfc_expr * x, gfc_expr * s)
  {
    gfc_expr *result;
!   float rval;
!   double val, eps;
!   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)
      return NULL;

!   k = gfc_validate_kind (x->ts.type, x->ts.kind, false);

    result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where);

!   val = mpfr_get_d (x->value.real, GFC_RND_MODE);
!   p = gfc_real_kinds[k].digits;
!
!   eps = 1.;
!   for (i = 1; i < p; ++i)
!     {
!       eps = eps / 2.;
!     }
!
!   /* TODO we should make sure that 'float' matches kind 4 */
!   match_float = gfc_real_kinds[k].kind == 4;
!   if (mpfr_cmp_ui (s->value.real, 0) > 0)
      {
!       if (match_float)
        {
!         rval = (float) val;
!         rval = rval + eps;
!         mpfr_set_d (result->value.real, rval, GFC_RND_MODE);
!       }
!       else
!       {
!         val = val + eps;
!         mpfr_set_d (result->value.real, val, GFC_RND_MODE);
        }
      }
!   else if (mpfr_cmp_ui (s->value.real, 0) < 0)
      {
!       if (match_float)
!       {
!         rval = (float) val;
!         rval = rval - eps;
!         mpfr_set_d (result->value.real, rval, GFC_RND_MODE);
!       }
!       else
        {
!         val = val - eps;
!         mpfr_set_d (result->value.real, val, GFC_RND_MODE);
        }
      }
    else
      {
!       gfc_error ("Invalid second argument of NEAREST at %L", &s->where);
        gfc_free (result);
        return &gfc_bad_expr;
      }
--- 2311,2357 ----
  gfc_simplify_nearest (gfc_expr * x, gfc_expr * s)
  {
    gfc_expr *result;
!   mpfr_t ulp;
!   int direction;

!   if (x->expr_type != EXPR_CONSTANT || s->expr_type != EXPR_CONSTANT)
      return NULL;

!   /* TODO: Use mpfr_nextabove and mpfr_nextbelow once we move to a
!      newer version of mpfr.  */

    result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where);
+   mpfr_init (ulp);
+   mpfr_set (ulp,
+           gfc_real_kinds[gfc_validate_kind (BT_REAL, x->ts.kind, 0)].epsilon,
+           GFC_RND_MODE);

!   direction = mpfr_cmp_ui (s->value.real, 0);
!   if (direction > 0)
      {
!       /* mpfr_add_one_ulp (result->value.real);  (after initializing
!        it to x->value.real, of course) didn't do the trick.  */
!       do
        {
!         mpfr_add (result->value.real, x->value.real, ulp, GFC_RND_MODE);
!         mpfr_mul_ui (ulp, ulp, 2, GFC_RND_MODE);
        }
+       while (mpfr_cmp (result->value.real, x->value.real) == 0);
      }
!   else if (direction < 0)
      {
!       /* As above but with mpfr_sub_one_ulp  */
!       do
        {
!         mpfr_sub (result->value.real, x->value.real, ulp, GFC_RND_MODE);
!         mpfr_mul_ui (ulp, ulp, 2, GFC_RND_MODE);
        }
+       while (mpfr_cmp (result->value.real, x->value.real) == 0);
      }
    else
      {
!       gfc_error ("Second argument of NEAREST at %L may not be zero",
!                &s->where);
        gfc_free (result);
        return &gfc_bad_expr;
      }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]