Thread overview
Floating point constant folding bug?
Mar 15, 2013
Johannes Pfau
Mar 15, 2013
Iain Buclaw
Mar 15, 2013
Johannes Pfau
Mar 15, 2013
Iain Buclaw
Mar 15, 2013
Johannes Pfau
Mar 15, 2013
Iain Buclaw
March 15, 2013
writefln("%f\n%f", cast(float)cast(int)float.infinity, float.infinity);

writes
---
2147483648.000000
inf
---

-fdump-tree-original
---
writefln ({.length=5, .ptr="%f\n%f"}, 2.147483647e+9,  Inf);
---

The same conversion at runtime produces the expected result.

Is this a gdc or gcc bug or is this expected?
March 15, 2013
On 15 March 2013 15:15, Johannes Pfau <nospam@example.com> wrote:

> writefln("%f\n%f", cast(float)cast(int)float.infinity, float.infinity);
>
> writes
> ---
> 2147483648.000000
> inf
> ---
>
> -fdump-tree-original
> ---
> writefln ({.length=5, .ptr="%f\n%f"}, 2.147483647e+9,  Inf);
> ---
>
> The same conversion at runtime produces the expected result.
>
> Is this a gdc or gcc bug or is this expected?
>

GCC bug, try the same in C and see if it produces the same result.

-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';


March 15, 2013
Forget what I've said, I somehow read that code as a bitwise/reinterpret cast but of course the code does an integer/float conversion so it's probably OK.

This is more interesting:

---
    float f = float.infinity;
    float f2 = float.max;
    int i = cast(int) f;
    int i2 = cast(int) f2;
    writefln("0x%x == int.min(0x%x)", i, int.min);
    writefln("0x%x == int.max(0x%x)", cast(int)float.infinity, int.max);
    writefln("0x%x == int.min(0x%x)", i2, int.min);
    writefln("0x%x == int.max(0x%x)", cast(int)float.max, int.max);
---

const folding expands to int.max, but the same code at runtime expands to int.min. C does not define what happens if too large float values are cast into ints. Do you know if D somehow defines this?

(There's a failing test in the test suite which assumes that the result is int.min in all cases above)
March 15, 2013
On 15 March 2013 18:35, Johannes Pfau <nospam@example.com> wrote:

> Forget what I've said, I somehow read that code as a bitwise/reinterpret cast but of course the code does an integer/float conversion so it's probably OK.
>
> This is more interesting:
>
> ---
>     float f = float.infinity;
>     float f2 = float.max;
>     int i = cast(int) f;
>     int i2 = cast(int) f2;
>     writefln("0x%x == int.min(0x%x)", i, int.min);
>     writefln("0x%x == int.max(0x%x)", cast(int)float.infinity, int.max);
>     writefln("0x%x == int.min(0x%x)", i2, int.min);
>     writefln("0x%x == int.max(0x%x)", cast(int)float.max, int.max);
> ---
>
> const folding expands to int.max, but the same code at runtime expands to int.min. C does not define what happens if too large float values are cast into ints. Do you know if D somehow defines this?
>
> (There's a failing test in the test suite which assumes that the result is int.min in all cases above)
>


I think the behaviour from DMD is more incidental than intended.  They use C's FLOAT_INFINITY, etc, macros. But because of the way it's written, gcc doesn't optimise the use of the value.   Whereas with gdc, because it uses gcc's real_t types, values of extreme numbers may change to be either 2147483647 or -2147483648 depending on whether -O is used.  As I said, in most cases you can see the same behaviour in C.

I can see if there might be some flag I can set to try and make gcc's codegen more safe for floats, but that might have impact on runtime.


-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';


March 15, 2013
Am Fri, 15 Mar 2013 20:20:14 +0000
schrieb Iain Buclaw <ibuclaw@ubuntu.com>:

> On 15 March 2013 18:35, Johannes Pfau <nospam@example.com> wrote:
> 
> > Forget what I've said, I somehow read that code as a bitwise/reinterpret cast but of course the code does an integer/float conversion so it's probably OK.
> >
> > This is more interesting:
> >
> > ---
> >     float f = float.infinity;
> >     float f2 = float.max;
> >     int i = cast(int) f;
> >     int i2 = cast(int) f2;
> >     writefln("0x%x == int.min(0x%x)", i, int.min);
> >     writefln("0x%x == int.max(0x%x)", cast(int)float.infinity,
> > int.max); writefln("0x%x == int.min(0x%x)", i2, int.min);
> >     writefln("0x%x == int.max(0x%x)", cast(int)float.max, int.max);
> > ---
> >
> > const folding expands to int.max, but the same code at runtime expands to int.min. C does not define what happens if too large float values are cast into ints. Do you know if D somehow defines this?
> >
> > (There's a failing test in the test suite which assumes that the result is int.min in all cases above)
> >
> 
> 
> I think the behaviour from DMD is more incidental than intended. They use C's FLOAT_INFINITY, etc, macros. But because of the way it's written, gcc doesn't optimise the use of the value.   Whereas with gdc, because it uses gcc's real_t types, values of extreme numbers may change to be either 2147483647 or -2147483648 depending on whether -O is used.  As I said, in most cases you can see the same behaviour in C.
> 
> I can see if there might be some flag I can set to try and make gcc's codegen more safe for floats, but that might have impact on runtime.
> 
> 

I think in this case GCC might intentionally use saturating overflows. I just found this message:

http://gcc.gnu.org/ml/gcc-patches/2003-09/msg02090.html

(This doesn't explain though what the test (constfold.d:test2) in the
dmd testsuite is actually supposed to test...)
March 15, 2013
On 15 March 2013 22:00, Johannes Pfau <nospam@example.com> wrote:

> Am Fri, 15 Mar 2013 20:20:14 +0000
> schrieb Iain Buclaw <ibuclaw@ubuntu.com>:
>
> > On 15 March 2013 18:35, Johannes Pfau <nospam@example.com> wrote:
> >
> > > Forget what I've said, I somehow read that code as a bitwise/reinterpret cast but of course the code does an integer/float conversion so it's probably OK.
> > >
> > > This is more interesting:
> > >
> > > ---
> > >     float f = float.infinity;
> > >     float f2 = float.max;
> > >     int i = cast(int) f;
> > >     int i2 = cast(int) f2;
> > >     writefln("0x%x == int.min(0x%x)", i, int.min);
> > >     writefln("0x%x == int.max(0x%x)", cast(int)float.infinity,
> > > int.max); writefln("0x%x == int.min(0x%x)", i2, int.min);
> > >     writefln("0x%x == int.max(0x%x)", cast(int)float.max, int.max);
> > > ---
> > >
> > > const folding expands to int.max, but the same code at runtime expands to int.min. C does not define what happens if too large float values are cast into ints. Do you know if D somehow defines this?
> > >
> > > (There's a failing test in the test suite which assumes that the result is int.min in all cases above)
> > >
> >
> >
> > I think the behaviour from DMD is more incidental than intended. They use C's FLOAT_INFINITY, etc, macros. But because of the way it's written, gcc doesn't optimise the use of the value.   Whereas with gdc, because it uses gcc's real_t types, values of extreme numbers may change to be either 2147483647 or -2147483648 depending on whether -O is used.  As I said, in most cases you can see the same behaviour in C.
> >
> > I can see if there might be some flag I can set to try and make gcc's codegen more safe for floats, but that might have impact on runtime.
> >
> >
>
> I think in this case GCC might intentionally use saturating overflows. I just found this message:
>
> http://gcc.gnu.org/ml/gcc-patches/2003-09/msg02090.html
>
> (This doesn't explain though what the test (constfold.d:test2) in the
> dmd testsuite is actually supposed to test...)
>


It tests an incidental feature of dmd-generated code that got turned into a test case.  Rather than something defined in the spec.

-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';