Date: Fri, 27 Jun 2008 03:00:11 GMT From: Bruce Evans <brde@optusnet.com.au> To: freebsd-i386@FreeBSD.org Subject: Re: i386/125011: precision of constants for long double Message-ID: <200806270300.m5R30Bo1031380@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR i386/125011; it has been noted by GNATS. From: Bruce Evans <brde@optusnet.com.au> To: Satoshi Kimura <satosi.kimura@nifty.FreeBSD.ORG>, com@FreeBSD.org Cc: freebsd-gnats-submit@FreeBSD.org, freebsd-i386@FreeBSD.org Subject: Re: i386/125011: precision of constants for long double Date: Fri, 27 Jun 2008 12:51:47 +1000 (EST) On Thu, 26 Jun 2008, Satoshi Kimura wrote: >> Description: > 1. problem > On rather new environment of FreeBSD (ex. 6.2, 7.0), > standard gcc (i.e /usr/bin/gcc) makes strange code > concerning "long double". The precision of all constants > of "long double" are rounded to that of "double". In addition, > if we add -m128bit-long-double option to gcc, this behavior > did not appear. I think not rounding for -m128bit-long-double is a bug, but it should be considered a feature, since there seems to be no other way to generate full precision for long doubles. It seems to work for compile time evaluation too: %%% long double lc; lc = 1.0L + LDBL_EPSILON; %%% Note that <float.h> is broken by default -- the LDBL_EPSILON in it doesn't actually work, since compile time expressions are evaluated in the default runtime precision which is plain double and the LDBL_EPSILON in <float.h> is only correct for the non-default precision of extended; thus 1.0L + LDBL_EPSILON always gives 1.0L at compile time, while at runtime it does the same by default, but if the runtime precision is changed to extended, then it actually gives the correct result of 1.0L plus a little. The above paragraph is with the default compiler options. -m128bit-long-double apparently causes the evaluation to be done in extended precision, so LDBL_EPSILON works in expressions at compile time, but gives results inconsistent with the default at runtime. > Historically, precision of constants of "long double" were > as follows: > > FreeBSD gcc 96bit 128bit > 2.2.6 2.2.2.1 NR - > 3.4 2.7.2.3 NR - > 4.9 2.95.4 NR - > 3.0.4 NR NR > 5.3 3.2.3 NR NR > 3.3.5 R R <- (1) gcc-3.3.3 in 5.2-CURRENT also generates garbage in the unused top 32 bits of a 128-bit long double. This is fixed in at least gcc-4.2.1 in 8.0-CURRENT. > 3.4.2 NR NR <- (2) > 6.2 3.4.6 R NR <- (3) > 6.3 3.4.6 R NR > 4.2.4 R NR > 7.0 4.2.1 R NR > > Meanings of this table are as follows: > FreeBSD : version of FreeBSD (RELEASE) > gcc : version of gcc > 96bit : 96bit long double > 128bit : 128bit long double (compiled with -m128bit-long-double option) > NR : not rounded, i.e keep precision of long double. > R : rounded to precision of double. > > 2. question > On above table, modification from (2) to (3) was made by > discussions at > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17778 > > The reason of this midification was as follows: >> On FreeBSD/i386, FPU precision is set to 53 bits to avoid problems with extra >> precision and double rounding for doubles. gcc understands this and evaluates >> FP constants in 53-bit precision, even for long doubles. > > He compared (1) and (2) on above table, and concluded to > resume the condition of (1). But, I cannot find the reason > that 128bit "long double" did not modified. ((3) on above table.) > > The most impotant question is that his understanding above is > correct or not ? If false, this modification is to be avoided. > Or, if true, 128bit "long double" is also to be modified. I think it is just a bug that -m128-bit-long double gives a different handling of precision. According to gcc.info, this and the -m96bit-long-double options are is only intended to control the size of the long double type. It is explicitly stated that "neither of these options enable any extra precision over the x87 standard of 80 bits for a long double". But FreeBSD doesn't use the standard precision and gcc.info doesn't say anything about this. There should be a way to generate long double constants with full precision intentionally, without breaking the ABI by using 128-bit ones. Similarly for the compile time precision. Similarly for rounding modes. FreeBSD now uses horrible complications in tables of long double constants in files like k_tanl.c in order to avoid the problem of the compiler "always" giving plain double precision. I once tried -m96-bit-long-double to get full precision, but it didn't work. I didn't know about -m128-bit-long-double, and it didn't give extra precision at the time (with gcc-3.3.3). The tables now obtain full precision by representing long doubles as the some of 2 doubles. This is actually the fastest way to handle long doubles on some i386's, but doing it as an optimization belongs in the compiler. gcc already does the related optimization of representing double constants (including non-literal ones, even in arrays in some cases) as floats if float precision is enough. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200806270300.m5R30Bo1031380>