Port-amd64 archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Changing the default i387 precision (compiler float constant evaluation)



On 12 May, 2013, at 22:00 , Dennis Ferguson 
<dennis.c.ferguson%gmail.com@localhost> wrote:
[...]

Attached is a program to show the problems with C99 compliance and
general unhappiness caused by the current default setting of the x87
precision on NetBSD.  The program evaluates

    1 - ((4/x) - 1) * x

for x==3.0 both as a compile time constant and at run time, and can
be compiled to do so in any of the 3 floating point types.  In
exact arithmetic the result is precisely zero so the greater the
precision with which the expression is evaluated the closer to
zero the result should be.

Here are the results for amd64 and i386 gcc, with the program
compiled for each of the 3 floating point types and with the standard
set to C99:

  $ gcc -std=c99 -DFLOAT -O -o try try.c
  $ ./try
  (8 0 4 1.19209e-07):  compiler = -1.19209e-07  run_time = -1.19209e-07
  $ gcc -std=c99 -DDOUBLE -O -o try try.c
  $ ./try
  (8 0 8 2.22045e-16):  compiler = 2.22045e-16  run_time = 2.22045e-16
  $ gcc -std=c99 -O -o try try.c
  $ ./try
  (8 0 16 1.08420e-19):  compiler = -1.08420e-19  run_time = 2.22045e-16
  $ gcc -m32 -std=c99 -DFLOAT -O -o try try.c
  $ ./try
  (4 2 4 1.19209e-07):  compiler = -1.08420e-19  run_time = 2.22045e-16
  $ gcc -m32 -std=c99 -DDOUBLE -O -o try try.c
  $ ./try
  (4 2 8 2.22045e-16):  compiler = -1.08420e-19  run_time = 2.22045e-16
  $ gcc -m32 -std=c99 -O -o try try.c
  $ ./try
  (4 2 12 1.08420e-19):  compiler = -1.08420e-19  run_time = 2.22045e-16

The values in (...) are sizeof(long), FLT_EVAL_METHOD, sizeof(floating_type)
used for the evaluation and XXX_EPSILON for floating_type.  Results closer
to 0 are more precise.  Any result which is significantly larger in magnitude
than XXX_EPSILON has been computed with less than the precision claimed for
the type; this is the case for amd64 and i386 long double computations, and
would be fixed by changing the default i387 precision.  All the i386
compiler-evaluated results are consistent with the FLT_EVAL_METHOD of 2,
and the value of LDBL_EPSILON, but the run time results are not.  Note
that while the letter of the C standard allows compile-time evaluation
of constant floating point expressions to be performed more precisely than
the run time, as is the case for the above i386 behaviour, it is
always better if the compile-time and execution-time evaluations match
precisely since that avoids having the results produced by a floating point
programs change with the optimization level due to this, which in turn makes
it easier to find real problems caused by the compiler's optimizer.  Changing 
the
default x87 precision to that of the 10-byte IEEE 754 format would make
the C99 compile-time and run-time behaviour fully consistent, and would
make the behaviour match the C99 standard where it does not now.

All of this makes perfect sense to me.  The only thing I don't get is that,
while the compiler clearly knows how it is supposed to behave for standard
C, by default it apparently instead provides "GNU" C with the following
behaviour for i386:

  $ gcc -m32 -std=gnu99 -DFLOAT -o try try.c
  $ ./try
  (4 2 4 1.19209e-07):  compiler = -1.19209e-07  run_time = 2.22045e-16
  $ gcc -m32 -std=gnu99 -DDOUBLE -o try try.c
  $ ./try
  (4 2 8 2.22045e-16):  compiler = 2.22045e-16  run_time = 2.22045e-16
  $ gcc -m32 -std=gnu99 -o try try.c
  $ ./try
  (4 2 12 1.08420e-19):  compiler = -1.08420e-19  run_time = 2.22045e-16

This does not provide an argument against changing the x87 precision since
no setting of the x87 precision is going to be consistent with that and,
given this, it is still better to set the x87 to fix long double and produce
better arithmetic in general.  I just don't get why it does that.

In any case, I think changing the x87 precision to that of the 10-byte
IEEE 754 extended format is exactly the right thing to do.  The current
state breaks long double on both architectures and is inconsistent with
a standard compiler for all three floating point types for i386.

Dennis Ferguson

Attachment: try.c
Description: Binary data

Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail



Home | Main Index | Thread Index | Old Index