The following program shows that the casts to long double are not taken into account when the result to stored to a variable of type double. This bug occurs with gcc from 3.4 to 4.3.1, but didn't occur with gcc 3.3. The bug can be reproduced on a Linux/x86_64 machine (i.e. where the "double" type corresponds to the IEEE-754 double precision and the "long double" type corresponds to the traditional x86 extended precision) with the arguments: 4294967219 4294967429 (these arguments allow the double rounding effect to be visible). #include <stdio.h> #include <stdlib.h> int main (int argc, char **argv) { double a, b, c, d, e; long double al, bl, dl, el; if (argc != 3) exit (1); a = atof (argv[1]); b = atof (argv[2]); al = a; bl = b; c = a * b; d = (long double) a * (long double) b; e = al * bl; dl = (long double) a * (long double) b; el = al * bl; printf ("a = %.0f\n", a); printf ("b = %.0f\n", b); printf ("c = %.0f\n", c); printf ("d = %.0f\n", d); printf ("e = %.0f\n", e); printf ("dl = %.0Lf\n", dl); printf ("el = %.0Lf\n", el); return 0; } Incorrect result (with gcc 3.4 to gcc 4.3.1): a = 4294967219 b = 4294967429 c = 18446744314227707904 d = 18446744314227707904 e = 18446744314227712000 dl = 18446744314227709952 el = 18446744314227709952 Correct result (as given by gcc 3.3) is the same except: d = 18446744314227712000 Note: I compiled with the options -std=c99 -Wall -pedantic.
To make things clear, perhaps I should have added: #if __STDC__ == 1 && __STDC_VERSION__ >= 199901 && defined(__STDC_IEC_559__) #pragma STDC FP_CONTRACT OFF printf ("__STDC_IEC_559__ defined:\n" "The implementation shall conform to the IEEE-754 standard.\n" "FLT_EVAL_METHOD is %d (see ISO/IEC 9899, 5.2.4.2.2#7).\n\n", (int) FLT_EVAL_METHOD); #endif which outputs: __STDC_IEC_559__ defined: The implementation shall conform to the IEEE-754 standard. FLT_EVAL_METHOD is 0 (see ISO/IEC 9899, 5.2.4.2.2#7). So, one can't even say that the value of d is correct because it is the same as the exact result rounded to double precision. The fact that the double rounding doesn't occur is a bug here.
Testcase double foo (double x, double y) { return (long double)x * (long double)y; } where we fold the multiplication to x * y. This is only ok with -funsafe-math-optimizations (like any other conversions removing FP operations). It is of course also ok if we for some reason know that x * y is exactly representable in both double and long double. It is convert_to_real doing this optimization.
Subject: Re: cast to long double not taken into account when result stored to a double On Sat, 21 Jun 2008, rguenth at gcc dot gnu dot org wrote: > It is convert_to_real doing this optimization. convert_to_real is also responsible for the problematic conversions in bug 35202. I didn't try to argue the double rounding issues for those conversions, only the errno issue, since I don't have an example for the double rounding affecting those function call conversions (and right now implementations of many of the functions will not typically be correctly rounding - but that could change if C1x follows the new IEEE 754 revision's recommendation of many more correctly rounded functions). But it is potentially an issue for the conversions of function calls as well as the plain arithmetic example of this bug.
Subject: Bug 36578 Author: jsm28 Date: Wed Oct 29 17:05:42 2008 New Revision: 141432 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=141432 Log: PR middle-end/36578 * convert.c (convert_to_real): Do not optimize conversions of binary arithmetic operations between binary and decimal floating-point types. Consider mode of target type in determining decimal type for arithmetic. Unless flag_unsafe_math_optimizations, do not optimize binary conversions where this may change rounding behavior. * real.c (real_can_shorten_arithmetic): New. * real.h (real_can_shorten_arithmetic): Declare. testsuite: * gcc.dg/dfp/convert-bfp-13.c, gcc.dg/dfp/convert-bfp-14.c, gcc.dg/dfp/convert-dfp-fold-2.c, gcc.target/i386/pr36578-1.c, gcc.target/i386/pr36578-2.c: New tests. Added: trunk/gcc/testsuite/gcc.dg/dfp/convert-bfp-13.c trunk/gcc/testsuite/gcc.dg/dfp/convert-bfp-14.c trunk/gcc/testsuite/gcc.dg/dfp/convert-dfp-fold-2.c trunk/gcc/testsuite/gcc.target/i386/pr36578-1.c trunk/gcc/testsuite/gcc.target/i386/pr36578-2.c Modified: trunk/gcc/ChangeLog trunk/gcc/convert.c trunk/gcc/real.c trunk/gcc/real.h trunk/gcc/testsuite/ChangeLog
Fixed for 4.4.
Subject: Bug 36578 Author: janis Date: Wed Feb 25 22:08:55 2009 New Revision: 144436 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=144436 Log: 2009-02-25 Janis Johnson <janis187@us.ibm.com> gcc/ Backport from mainline: 2008-10-29 Joseph Myers <joseph@codesourcery.com> PR middle-end/36578 * convert.c (convert_to_real): Do not optimize conversions of binary arithmetic operations between binary and decimal floating-point types. Consider mode of target type in determining decimal type for arithmetic. Unless flag_unsafe_math_optimizations, do not optimize binary conversions where this may change rounding behavior. * real.c (real_can_shorten_arithmetic): New. * real.h (real_can_shorten_arithmetic): Declare. gcc/testsuite/ Backport from mainline: 2008-10-29 Joseph Myers <joseph@codesourcery.com> PR middle-end/36578 * gcc.dg/dfp/convert-bfp-13.c, gcc.dg/dfp/convert-bfp-14.c, gcc.dg/dfp/convert-dfp-fold-2.c, gcc.target/i386/pr36578-1.c, gcc.target/i386/pr36578-2.c: New tests. Added: branches/gcc-4_3-branch/gcc/testsuite/gcc.dg/dfp/convert-bfp-13.c branches/gcc-4_3-branch/gcc/testsuite/gcc.dg/dfp/convert-bfp-14.c branches/gcc-4_3-branch/gcc/testsuite/gcc.dg/dfp/convert-dfp-fold-2.c branches/gcc-4_3-branch/gcc/testsuite/gcc.dg/dfp/pr39034.c branches/gcc-4_3-branch/gcc/testsuite/gcc.target/i386/pr36578-1.c branches/gcc-4_3-branch/gcc/testsuite/gcc.target/i386/pr36578-2.c Modified: branches/gcc-4_3-branch/gcc/ChangeLog branches/gcc-4_3-branch/gcc/convert.c branches/gcc-4_3-branch/gcc/real.c branches/gcc-4_3-branch/gcc/real.h branches/gcc-4_3-branch/gcc/testsuite/ChangeLog