Skip site navigation (1)Skip section navigation (2)
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>