clang gets numerical underflow wrong, please fix.
Steve Kargl
sgk at troutmask.apl.washington.edu
Mon Mar 14 00:40:03 UTC 2016
On Mon, Mar 14, 2016 at 01:02:20AM +0100, Dimitry Andric wrote:
> On 13 Mar 2016, at 21:10, Steve Kargl <sgk at troutmask.apl.washington.edu> wrote:
> > Thanks for the quick reply. But, it must be using an 80-bit
> > extended double instead of a double for storage. This variation
> >
> > #include <fenv.h>
> > #include <stdio.h>
> >
> > int
> > main(void)
> > {
> > int i;
> > // float x = 1.f;
> > double x = 1.;
> > i = 0;
> > feclearexcept(FE_ALL_EXCEPT);
> > do {
> > x /= 2;
> > i++;
> > } while(!fetestexcept(FE_UNDERFLOW));
> > if (fetestexcept(FE_UNDERFLOW)) printf("FE_UNDERFLOW: ");
> > printf("x = %e after %d iterations\n", x, i);
> >
> > return 0;
> > }
> >
> > yields
> >
> > % cc -O -o z b.c -lm && ./z
> > FE_UNDERFLOW: x = 0.000000e+00 after 16435 iterations
> >
> > It should be 1075 iterations.
> >
> > Note, there is a similar issue with OVERFLOW. The upshot is
> > that clang on current is probably miscompiling libm.
>
> With this example, I also get different results from gcc (4.8.5),
> depending on the optimization level:
>
> $ gcc -O underflow-iter.c -o underflow-iter-gcc -lm
> $ ./underflow-iter-gcc
> FE_UNDERFLOW: x = 0.000000e+00 after 1075 iterations
> $ gcc -O2 underflow-iter.c -o underflow-iter-gcc -lm
> $ ./underflow-iter-gcc
> FE_UNDERFLOW: x = 0.000000e+00 after 16435 iterations
>
> Similar for the overflow case:
>
> $ gcc -O overflow-iter.c -o overflow-iter-gcc -lm
> $ ./overflow-iter-gcc
> FE_OVERFLOW: x = inf after 1024 iterations
> $ gcc -O2 overflow-iter.c -o overflow-iter-gcc -lm
> $ ./overflow-iter-gcc
> FE_OVERFLOW: x = inf after 16384 iterations
>
> Are we depending on some sort of subtle undefined behavior here?
I don't know. From n1256.pdf, 6.5.5, I can find
The result of the binary * operator is the product of the operands.
I can't find what happens when one operand is DBL_MAX and the
other is greater than 1. The result is clearly an overflow
condition. Annex F is normative text, which defers to IEC
60559. F.3 states
-- The +, -, *, and / operators provide the IEC 60559 add,
subtract, multiply, and divide operations.
Annex F contains alot of text about "#pragma STDC FENV_ACCESS ON",
but of course neither gcc nor clang implement this pragma. In
particular, in F.8.1 one has
Floating-point arithmetic operations ... may entail side effects
which optimization shall honor, at least where the state of the
FENV_ACCESS pragma is ``on''. The flags ... in the floating-point
environment may be regarded as global variables; floating-point
operations (+, *, etc.) implicitly ... write the flags.
However, F.7.1 has
F.7.1 Environment management
IEC 60559 requires that floating-point operations implicitly raise
floating-point exception status flags, ... When the state for the
FENV_ACCESS pragma (defined in <fenv.h>) is ``on'', these changes
to the floating-point state are treated as side effects which respect
sequence points.313)
313) If the state for the FENV_ACCESS pragma is ``off'', the
implementation is free to assume the floating-point control
modes will be the default ones and the floating-point status
flags will not be tested, which allows certain optimizations
(see F.8).
So, I'm guessing clang/llvm developers aer going to claim that the
lack of implementation of the FENV_ACCESS pragme means "off". So,
clang is unsuitable for real floating-point development.
--
Steve
More information about the freebsd-toolchain
mailing list