With a recent gfortran, the following compiles, but generates the wrong results: ! http://gcc.gnu.org/ml/fortran/2005-04/msg00139.html real*8 :: a integer*8 :: i1,i2 a=.4999999999999999444888487687421729788184165954589843750_8 i2=NINT(.4999999999999999444888487687421729788184165954589843750_8) i1=NINT(a) ! 0.499999999999999944488848768742 0 0 write(6,'(F40.30,2I2)') a,i1,i2 IF (i1.NE.i2) CALL ABORT() a=4503599627370497.0_8 i1=NINT(a,KIND=8) i2=NINT(4503599627370497.0_8,KIND=8) ! 4503599627370497 4503599627370497 4503599627370497 write(6,*) 4503599627370497_8,i1,i2 IF (i1.NE.i2) CALL ABORT() END
Confirmed on x86_64-linux, but somehow it doesn't happen on i386. The reason why it fails and the way to fix it are given in the ML link given by the reporter.
*** Bug 31208 has been marked as a duplicate of this bug. ***
Created attachment 13228 [details] Patch for this bug This is a patch following exactly the very good explanation done in the mailing-list post pointed by the testcase. I need to work on a good testcase exercing this with differents kinds. And there also is a question for middle-end maintainers about how to get the longest floating point type in a systematic way.
Created attachment 13532 [details] New patch Here's a new patch from a completely different perspective, using C99 lround and llround functions (and their float and long double variants).
is this patch still OK ?
(In reply to comment #5) > is this patch still OK ? The lround patch should be OK on C99 targets, but it would probably break things on non-C99 targets, which is why I didn't submit it for formal review. I should have some time to look into it later, but the last weeks have been a complete chaos (PhD defence and finishing every little project I had in my group).
(In reply to comment #6) > (In reply to comment #5) > > is this patch still OK ? > > The lround patch should be OK on C99 targets, but it would probably break > things on non-C99 targets, which is why I didn't submit it for formal review. I On non-c99 targets, gfortran supplies roundf and roundl. You could do (GFC_INTEGER_?) roundl() for lroundl().
Subject: Bug 31202 Author: fxcoudert Date: Fri Aug 3 21:26:10 2007 New Revision: 127185 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=127185 Log: PR fortran/31202 * f95-lang.c (gfc_init_builtin_functions): Defin builtins for lround{f,,l} and llround{f,,l}. * trans-intrinsic.c (build_fix_expr): Generate calls to the {l,}round{f,,l} functions. * intrinsics/c99_functions.c (roundl,lroundf,lround,lroundl, llroundf,llround,llroundl): New functions. * c99_protos.h (roundl,lroundf,lround,lroundl,llroundf,llround, llroundl): New prototypes. * configure.ac: Check for lroundf, lround, lroundl, llroundf, llround and llroundl. * configure: Regenerate. * Makefile.in: Regenerate. * config.h.in: Regenerate. * gfortran.dg/nint_2.f90: New test. Added: trunk/gcc/testsuite/gfortran.dg/nint_2.f90 Modified: trunk/gcc/fortran/ChangeLog trunk/gcc/fortran/f95-lang.c trunk/gcc/fortran/trans-intrinsic.c trunk/gcc/testsuite/ChangeLog trunk/libgfortran/ChangeLog trunk/libgfortran/Makefile.in trunk/libgfortran/c99_protos.h trunk/libgfortran/config.h.in trunk/libgfortran/configure trunk/libgfortran/configure.ac trunk/libgfortran/intrinsics/c99_functions.c
Well, we'll see if I broke any non-C99 target :)
Subject: Re: Incorrect rounding generated for NINT On Fri, 3 Aug 2007, fxcoudert at gcc dot gnu dot org wrote: > Well, we'll see if I broke any non-C99 target :) Yes, you did. :) NetBSD does not have lroundl (and not roundl, so lroundl is not added by intrinsics/c99_functions.c) with the result that linking with libgfortran fails with "undefined reference to `lroundl'". /Krister
Index: intrinsics/c99_functions.c =================================================================== --- intrinsics/c99_functions.c (revision 127224) +++ intrinsics/c99_functions.c (working copy) @@ -500,8 +500,9 @@ powf(float x, float y) /* Algorithm by Steven G. Kargl. */ -#if !defined(HAVE_ROUNDL) && defined(HAVE_CEILL) +#if !defined(HAVE_ROUNDL) #define HAVE_ROUNDL 1 +#if defined(HAVE_CEILL) /* Round to nearest integral value. If the argument is halfway between two integral values then round away from zero. */ @@ -527,6 +528,27 @@ roundl(long double x) return (-t); } } +#else + +/* Poor version of roundl for system that don't have ceill. */ +long double +roundl(long double x) +{ + if (x > DBL_MAX || x < -DBL_MAX) + { +#ifdef HAVE_NEXTAFTERL + static long double prechalf = nexafterl (0.5L, LDBL_MAX); +#else + static long double prechalf = 0.5L; +#endif + return (GFC_INTEGER_LARGEST) (x + (x > 0 ? prechalf : -prechalf)); + } + else + /* Use round(). */ + return round((double) x); +} + +#endif #endif #ifndef HAVE_ROUND
Subject: Bug 31202 Author: fxcoudert Date: Sun Aug 5 22:14:34 2007 New Revision: 127227 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=127227 Log: 2007-08-05 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org> PR fortran/31202 * intrinsics/c99_functions.c (roundl): Provide fallback implementation for systems without ceill. * c99_protos.h (roundl): Define prototype in all cases. Modified: trunk/libgfortran/ChangeLog trunk/libgfortran/c99_protos.h trunk/libgfortran/intrinsics/c99_functions.c