Bug List: (This bug is not in your last search results)   Show last search results      Search page      Enter new bug
Bug#: 13719
Product:  
Component:  
Status: RESOLVED
Resolution: INVALID
Assigned To: Not yet assigned to anyone <unassigned@gcc.gnu.org>
Host:
Reported against  
Priority:  
Severity:  
Target Milestone:  
 
 
Target:
Reporter: Guilhem Bichot <guilhem@mysql.com>
Add CC:
CC:
Remove selected CCs
Build:
URL:
Summary:
Keywords:
Known to work:
Known to fail:

Attachment Description Type Created Size Actions
Create a New Attachment (proposed patch, testcase, etc.) View All

Bug 13719 depends on: Show dependency tree
Show dependency graph
Bug 13719 blocks:

Additional Comments:






View Bug Activity   |   Format For Printing   |   Clone This Bug


Description:   Last confirmed: Opened: 2004-01-17 14:24
Hi!
I have read the "most reported non-bug" about floating-point precision, but I
think it's a real bug here; please take time to read.
I personally use 3.2.2 but colleague with 3.3.2 has the same bug too (with
same testcase and same compiler options). We use Linux (Mandrake & SuSE).

Here is test.cc:
#include <stdlib.h>

int main()
{
  return ((int)((atof("0.2")*atof("5.0"))>1.0));
}

Compile this with:
g++ -O0    -o test_bin test.cc
And in a shell execute:
./test_bin ; echo $?
I get 1, so comparison is done wrong.
Adding -ffloat-store does not remove the error.

Here is the problem in my humble opinion (using the output of g++ -S):
g++ -O0 -S test.cc:

        .file   "test.cc"
        .section        .rodata
.LC0:
        .string "0.2"
.LC1:
        .string "5.0"
        .text
        .align 2
.globl main
        .type   main,@function
main:
.LFB1:
        pushl   %ebp
.LCFI0:
        movl    %esp, %ebp
.LCFI1:
        subl    $8, %esp
.LCFI2:
        andl    $-16, %esp
        movl    $0, %eax
        subl    %eax, %esp
        subl    $12, %esp
        pushl   $.LC0
.LCFI3:
        call    atof
        addl    $16, %esp
        fstpl   -8(%ebp)
        subl    $12, %esp
        pushl   $.LC1
        call    atof
        addl    $16, %esp
        fldl    -8(%ebp)
**multiplication of the 2 numbers
        fmulp   %st, %st(1)
**result of multiplication (1.000000000000000056)
**is left in FPU
**and directly used for comparison, hence the problem
        fld1
        fxch    %st(1)
        fucompp
        fnstsw  %ax
        testb   $69, %ah
        sete    %al
        andl    $255, %eax
        leave
        ret
.LFE1:
.Lfe1:
        .size   main,.Lfe1-main
        .ident  "GCC: (GNU) 3.2.2 (Mandrake Linux 9.1 3.2.2-3mdk)"

I guess there should be some rounding (using fldl) between multiplication and
comparison; it does not make sense to do the comparison with the extra precision
of the FPU. In the next example we see it better.

If I add a few printf(), the error appears only with -O1 (or more): here is
test2.cc:
#include <stdlib.h>
#include <stdio.h>

main()
{
  double e = atof("0.2")*atof("5.0");
  if (e>1.0)
    printf("0.2 * 5.0 > 1.0 (ERROR)\n");
  else
    printf("0.2 * 5.0 <= 1.0 (OK)\n");
}

When built with g++ -O0 test2.cc it prints OK, with -01 it prints ERROR.
Here are snippets of the assembler code (the multiplication and comparison section):
with -O0:
<cut>
        fmull   -16(%ebp)
        fstpl   -8(%ebp)
        fldl    -8(%ebp)
        fld1
        fxch    %st(1)
        fucompp
<cut>
(see fldl which does the rounding of the multiplication result from FPU
precision to double precision).
With -O1:
<cut>
        fmulp   %st, %st(1)
        fld1
        fxch    %st(1)
        fucompp
<cut>
Again, the result of the multiplication (with precision of the FPU) is used
directly for comparison, without any rounding.

In the MySQL code which is were the problem originally arose (we had
SELECT ACOS(0.2*5.0) returning NULL), the problem appeared only with -O2 (or more).

I hope these testcases can be of use.
Guilhem Bichot (MySQL A.B.)

------- Comment #1 From Guilhem Bichot 2004-01-17 14:25 -------
Forgot to say: reproduced on processors AMD Athlon XP2000+ and Pentium III
Xeon.

------- Comment #2 From Andrew Pinski 2004-01-17 18:05 -------
Not a bug, it is connect to the most reported non-bug but GCC is allowed to
keep intermediate 
results in the excussive precision form which is happening here.  If you store
the multiplication into 
a tempary variable it works as you are expecting, this is not a bug.

------- Comment #3 From Guilhem Bichot 2004-01-17 19:54 -------
Thanks for your answer. However, the 2nd example I gave in the bug report
#include <stdlib.h>
#include <stdio.h>

main()
{
  double e = atof("0.2")*atof("5.0");
  if (e>1.0)
    printf("0.2 * 5.0 > 1.0 (ERROR)\n");
  else
    printf("0.2 * 5.0 <= 1.0 (OK)\n");
}
does "store the multiplication into a temporary variable" (quoting your words)
('e'), but it certainly does not "work as I am expecting" when compiled with -O1.
Could you please explain to me?

------- Comment #4 From Andrew Pinski 2004-01-17 20:02 -------
Still need -ffloat-store for the second case, the first case it does not matter
because of C rules and 
how -ffloat-store works.  Also you can use -mfpmath=sse to get the results you
are expecting on 
x86.

Bug List: (This bug is not in your last search results)   Show last search results      Search page      Enter new bug