[PATCH/gfortran] Chop bits of subnormal numbers
Steve Kargl
sgk@troutmask.apl.washington.edu
Sat May 7 21:25:00 GMT 2005
The attached is a brute force implementation of the chop
rounding recommended by rth for subnormal numbers in the
MPFR representation. A future version of MPFR will have
a more efficient and elegant function to perform this
operation.
2005-05-07 Steven G. Kargl <kargls@comcast.net>
* arith.c (gfc_check_integer_range): zero insignificant bits
in significands of subnormal numbers
--
Steve
-------------- next part --------------
Index: arith.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/arith.c,v
retrieving revision 1.26
diff -c -p -r1.26 arith.c
*** arith.c 14 Apr 2005 16:29:31 -0000 1.26
--- arith.c 7 May 2005 21:14:36 -0000
*************** gfc_check_integer_range (mpz_t p, int ki
*** 359,366 ****
return result;
}
-
-
/* Given a real and a kind, make sure that the real lies within the
range of the kind. Returns ARITH_OK, ARITH_OVERFLOW or
ARITH_UNDERFLOW. */
--- 359,364 ----
*************** gfc_check_real_range (mpfr_t p, int kind
*** 381,389 ****
if (mpfr_sgn (q) == 0)
retval = ARITH_OK;
else if (mpfr_cmp (q, gfc_real_kinds[i].huge) > 0)
! retval = ARITH_OVERFLOW;
else if (mpfr_cmp (q, gfc_real_kinds[i].subnormal) < 0)
retval = ARITH_UNDERFLOW;
else
retval = ARITH_OK;
--- 379,414 ----
if (mpfr_sgn (q) == 0)
retval = ARITH_OK;
else if (mpfr_cmp (q, gfc_real_kinds[i].huge) > 0)
! retval = ARITH_OVERFLOW;
else if (mpfr_cmp (q, gfc_real_kinds[i].subnormal) < 0)
retval = ARITH_UNDERFLOW;
+ else if (mpfr_cmp (q, gfc_real_kinds[i].tiny) < 0)
+ {
+ /* MPFR operates on a numbers with a given precision and enormous
+ exponential range. To represent subnormal numbers the exponent is
+ allowed to become smaller than emin, but always retains the full
+ precision. This function resets unused bits to 0 to alleviate
+ rounding problems. Note, a future version of MPFR will have a
+ mpfr_subnormalize() function, which handles this truncation in a
+ more efficient and robust way. */
+
+ int j, k;
+ char *bin, *s;
+ mp_exp_t e;
+
+ bin = mpfr_get_str(NULL, &e, gfc_real_kinds[i].radix, 0, p, GMP_RNDN);
+ k = gfc_real_kinds[i].digits - (gfc_real_kinds[i].min_exponent - e);
+ for (j = k; j < gfc_real_kinds[i].digits; j++)
+ bin[j] = '0';
+ /* Need space for '0.', bin, 'E', and e */
+ s = (char *) gfc_getmem(strlen(bin)+10);
+ sprintf(s, "0.%sE%d", bin, (int) e);
+ mpfr_set_str (p, s, gfc_real_kinds[i].radix, GMP_RNDN);
+ gfc_free(s);
+ gfc_free(bin);
+
+ retval = ARITH_OK;
+ }
else
retval = ARITH_OK;
More information about the Fortran
mailing list