[Units] test_trig fails on Sandia-darwin-4.4 (caused by compile-time evaluation of math functions)

The Units' test (libs/units/test/test_trig.cpp) fails on Sandia-darwin-4.4: http://tinyurl.com/3wherck The failure is caused by the fact that the results of `std::acos(0.2)` and `std::acos(d)` (double d = 0.2) are NOT equal on Sandia-darwin-4.4. On gcc-4.3 and newer versions, built-in math functions having constant arguments are evaluated at compile time using the MPFR (Multiple Precision Floating-Point Reliable) library. This happens even if optimization is disabled. So, the results of std::acos(0.2); // evaluated by the MPFR library at compile time and double d = 0.2; std::acos(d); // evaluated by the built-in function at run time are different. (If we compile with optimization enabled, the latter code is also evaluated by the MPFR library at compile time.) The solution to this problem is * Change BOOST_CHECK_EQUAL to BOOST_CHECK_CLOSE_FRACTION. or * Change `std::acos(0.2)` to `std::acos(d)` (with `double d = 0.2`) An interesting thing is that the test fails only on Sandia-darwin (x86-64) platform. On other platforms using gcc 4.3-4.6, the test runs successfully. I suspect that they have 80-bit registers and so the result of `std::acos(d)` is as accurate as the result of the MPFR library. Do you have any thoughts about this? Regards, Michel

On 08/21/2011 04:19 PM, Michel MORIN wrote:
The Units' test (libs/units/test/test_trig.cpp) fails on Sandia-darwin-4.4: http://tinyurl.com/3wherck
The failure is caused by the fact that the results of `std::acos(0.2)` and `std::acos(d)` (double d = 0.2) are NOT equal on Sandia-darwin-4.4.
On gcc-4.3 and newer versions, built-in math functions having constant arguments are evaluated at compile time using the MPFR (Multiple Precision Floating-Point Reliable) library. This happens even if optimization is disabled.
So, the results of std::acos(0.2); // evaluated by the MPFR library at compile time and double d = 0.2; std::acos(d); // evaluated by the built-in function at run time are different. (If we compile with optimization enabled, the latter code is also evaluated by the MPFR library at compile time.)
The solution to this problem is * Change BOOST_CHECK_EQUAL to BOOST_CHECK_CLOSE_FRACTION. or * Change `std::acos(0.2)` to `std::acos(d)` (with `double d = 0.2`)
An interesting thing is that the test fails only on Sandia-darwin (x86-64) platform. On other platforms using gcc 4.3-4.6, the test runs successfully. I suspect that they have 80-bit registers and so the result of `std::acos(d)` is as accurate as the result of the MPFR library. Do you have any thoughts about this?
This seems correct. The compile-time evaluation of GCC yields correctly-rounded results, which is not the case of the runtime evaluation. I don't know what BOOST_CHECK_CLOSE_FRACTION does, but I don't think there is any guarantee at all about the accuracy of the standard mathematical functions.

Mathias Gaunard wrote:
On 08/21/2011 04:19 PM, Michel MORIN wrote:
... So, the results of std::acos(0.2); // evaluated by the MPFR library at compile time and double d = 0.2; std::acos(d); // evaluated by the built-in function at run time are different. ...
This seems correct.
The compile-time evaluation of GCC yields correctly-rounded results, which is not the case of the runtime evaluation.
This kind of problems -- different results are obtained depending on whether they are evaluated at compile time or at run time -- might become more popular in C++0x due to constexpr. (And, wow, math functions are constexpr in gcc-4.7!)
I don't know what BOOST_CHECK_CLOSE_FRACTION does, but I don't think there is any guarantee at all about the accuracy of the standard mathematical functions.
Agreed. There is no guarantee about the accuracy, AFAIK. Regards, Michel

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Mathias Gaunard Sent: Sunday, August 21, 2011 3:56 PM To: boost@lists.boost.org Subject: Re: [boost] [Units] test_trig fails on Sandia-darwin-4.4 (caused by compile-time evaluation of math functions)
<snip>
I don't know what BOOST_CHECK_CLOSE_FRACTION does,
It allows an 'approximately equal' check, with a tolerance, usually an epsilon or two for built-in functions. BOOST_CHECK_CLOSE_FRACTION(v1, v2, std::numeric_limits<double>::epsilon()); Using exact comparison (BOOST_CHECK) is always dodgy for floating point.
but I don't think there is any guarantee at all about the accuracy of the standard mathematical functions.
Definitely not, especially for corner cases. Paul --- Paul A. Bristow, Prizet Farmhouse, Kendal LA8 8AB UK +44 1539 561830 07714330204 pbristow@hetp.u-net.com
participants (3)
-
Mathias Gaunard
-
Michel MORIN
-
Paul A. Bristow