From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30306 invoked by alias); 17 Jan 2004 14:24:47 -0000 Mailing-List: contact gcc-bugs-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-bugs-owner@gcc.gnu.org Received: (qmail 30299 invoked by uid 48); 17 Jan 2004 14:24:47 -0000 Date: Sat, 17 Jan 2004 14:24:00 -0000 From: "guilhem at mysql dot com" To: gcc-bugs@gcc.gnu.org Message-ID: <20040117142439.13719.guilhem@mysql.com> Reply-To: gcc-bugzilla@gcc.gnu.org Subject: [Bug c++/13719] New: 0.2*5.0>1.0 even with -O0, missing fldl probably X-Bugzilla-Reason: CC X-SW-Source: 2004-01/txt/msg01981.txt.bz2 List-Id: 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 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 #include 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: fmull -16(%ebp) fstpl -8(%ebp) fldl -8(%ebp) fld1 fxch %st(1) fucompp (see fldl which does the rounding of the multiplication result from FPU precision to double precision). With -O1: fmulp %st, %st(1) fld1 fxch %st(1) fucompp 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.) -- Summary: 0.2*5.0>1.0 even with -O0, missing fldl probably Product: gcc Version: 3.3.2 Status: UNCONFIRMED Severity: normal Priority: P2 Component: c++ AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: guilhem at mysql dot com CC: gcc-bugs at gcc dot gnu dot org http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13719