|
From: KHMan <kei...@gm...> - 2012-08-05 02:28:27
|
On 8/5/2012 6:21 AM, Martin Whitaker wrote:
> After updating to the latest version of the MinGW GCC (4.7.0), one
> of my regression tests started failing.
Interesting, it fails for me on MinGW gcc 3.4.5, MinGW 4.5.2 and
TDM gcc 4.5.2...
> I've isolated the problem
> to the following test case:
>
> #include<stdio.h>
> #include<math.h>
>
> volatile double scale = 3.0;
>
> int main(int argc, char *argv[])
> {
> printf("%20.20f\n", 123000.0 / pow(10.0, scale));
> printf("%d\n", (int)(123000.0 / pow(10.0, scale)));
> printf("%d\n", (int)(123000.0 / pow(10.0, 3.0)));
> }
>
> The output from this is:
>
> 123.00000000000000000000
> 122
> 123
>
>
> whereas I would have expected the middle number to also be 123.
>
> Is this allowed behaviour, or is it a bug? I realise double to int
> conversion is not necessarily exact, but it appears that the double
> value is an exact representation of the desired integer value, so I
> would have expected it to survive conversion. As shown by the third
> line of output, it does when the expression is evaluated at compile
> time.
Search for 'pow' in your math.h header file and you will find the
answer in a long comment block: "Excess precision when using a
64-bit mantissa for FPU math ops can cause unexpected results..."
Adding:
#include <fenv.h>
fesetenv(FE_PC53_ENV);
gives 123 for the second line. Or save it first. The assembly
output around the pow() in the second line is:
flds 32(%esp)
fstpl (%esp)
call _pow
fldl 16(%esp) ; loads 123000.0
fdivp %st, %st(1) ; divide with pow() on x87 stack
So the intermediate result was kept on the x87 stack, and the
final result isn't exact I suppose.
glibc wraps the i386 pow instruction and test for various special
cases and conditions, including appropriate integer arguments, in
order to guarantee exact results where possible.
--
Cheers,
Kein-Hong Man (esq.)
Kuala Lumpur, Malaysia
|