Summary: | gij - Incorrect result due to computations in extended precision on x86 | ||
---|---|---|---|
Product: | gcc | Reporter: | Debian GCC Maintainers <debian-gcc> |
Component: | libgcj | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | RESOLVED WONTFIX | ||
Severity: | normal | CC: | gcc-bugs, java-prs, vincent-gcc |
Priority: | P2 | ||
Version: | 3.4.1 | ||
Target Milestone: | --- | ||
Host: | Target: | i486-linux | |
Build: | Known to work: | ||
Known to fail: | Last reconfirmed: | 2005-09-24 15:56:22 |
Description
Debian GCC Maintainers
2004-06-21 19:58:29 UTC
Actually this is not a bug unless you use strictfp but IIRC strictfp does nothing to the problem anyways. I don't know very much about Java, but I've talked with someone who has some knowledge in Java and floating point, and according to him, Java FP arithmetic operations must round exactly in double precision (this is also confirmed by the documentation I could see). strictfp concerns the exponent range of the double precision vs extended precision, but this is not the problem here. Confirmed with HEAD. The problem doesn't occur with native compilation, it is a gij issue only. A bit more explanation. The problem is caused by the fact that 9007199254740994.0 + 0.9999847412109375 is carried out in extended precision, and the result is rounded to 9007199254740995. In double precision, the result of this calculation is rounded to 9007199254740994. When the extended-precision value is rounded to double for storing, it is rounded (again) to 9007199254740996. So, double rounding leads gij to return a value of d that is 2.0, whereas it should be 0.0. Note however, that the true accurate value for d, calculated at infinite precision, is 1-(2^-16). So, the absolute error for gcj is 1+(2^-16) and the absolute error with correct rounding is 1-(2^-16). (I'm not surprised this hasn't been reported as a problem with any real applications!) It might be worth setting the floating-point precision of gcj to double, but that would only fix the double-precision case, and I presume we'd still have the same double rounding problem for floats. And in any case, I do not know if libcalls would be affected by being entered with the FPU in round-to-double mode. We might end up breaking things. (In reply to comment #4) > Note however, that the true accurate value for d, calculated at infinite > precision, is 1-(2^-16). So, the absolute error for gcj is 1+(2^-16) and the > absolute error with correct rounding is 1-(2^-16). (I'm not surprised this > hasn't been reported as a problem with any real applications!) Note that some algorithms may be sensitive to this difference. I give an example in <http://www.vinc17.org/research/publi.en.html#Lef2005b> (The Euclidean division implemented with a floating-point division and a floor); the effect of extended precision is dealt with in Section 5. A second problem is the reproducilibity of the results on various architectures. Under probabilistic hypotheses, there should be something like 1 case over 2048 that is incorrectly rounded (in the real world, this is much less). > It might be worth setting the floating-point precision of gcj to double, but > that would only fix the double-precision case, and I presume we'd still have > the same double rounding problem for floats. Yes, however doubles are nowadays used much more often than floats, IMHO. I think that fixing the problem for the doubles would be sufficient (as it is probably too difficult to do better), though not perfect. > And in any case, I do not know if libcalls would be affected by being entered > with the FPU in round-to-double mode. We might end up breaking things. The only glibc function for which problems have been noticed is pow in corner cases. See <http://sources.redhat.com/bugzilla/show_bug.cgi?id=706>. And it is also inaccurate when the processor is configured in extended precision; so in any case, users shouldn't rely on it. I'd be interested in other cases, if any. More information here: <http://www.vinc17.org/research/extended.en.html> Closing as won't fix as libgcj (and the java front-end) has been removed from the trunk. |