@@ -32,16 +32,29 @@ import boost.safe_numbers;
3232
3333using namespace boost ::safe_numbers;
3434
35+ // Route the argument through a volatile so the reference std:: call is evaluated by the
36+ // runtime libm rather than constant-folded by the compiler. On 32-bit x86 (x87) some
37+ // libm transcendentals are not correctly rounded and differ from the compiler's folded
38+ // value by an ULP; forcing both the wrapper and the reference onto the same runtime call
39+ // keeps the bit-exact comparison valid.
40+ template <typename U>
41+ auto opaque (const U value) noexcept -> U
42+ {
43+ volatile U sink {value};
44+ return sink;
45+ }
46+
3547// Finite inputs: the wrapper delegates to the same std function on the same basis
3648// value, so the result is bit-identical and can be compared with exact equality.
3749template <typename T>
3850void test_finite ()
3951{
4052 using basis_type = typename T::basis_type;
4153
42- for (const auto x : {static_cast <basis_type>(0.0 ), static_cast <basis_type>(0.5 ),
43- static_cast <basis_type>(-0.5 ), static_cast <basis_type>(1.0 )})
54+ for (const auto raw : {static_cast <basis_type>(0.0 ), static_cast <basis_type>(0.5 ),
55+ static_cast <basis_type>(-0.5 ), static_cast <basis_type>(1.0 )})
4456 {
57+ const auto x {opaque (raw)};
4558 BOOST_TEST (sin (T{x}) == T{std::sin (x)});
4659 BOOST_TEST (cos (T{x}) == T{std::cos (x)});
4760 BOOST_TEST (tan (T{x}) == T{std::tan (x)});
@@ -50,10 +63,12 @@ void test_finite()
5063 BOOST_TEST (acos (T{x}) == T{std::acos (x)});
5164 }
5265
53- BOOST_TEST (atan2 (T{static_cast <basis_type>(1.0 )}, T{static_cast <basis_type>(1.0 )})
54- == T{std::atan2 (static_cast <basis_type>(1.0 ), static_cast <basis_type>(1.0 ))});
55- BOOST_TEST (atan2 (T{static_cast <basis_type>(-1.0 )}, T{static_cast <basis_type>(2.0 )})
56- == T{std::atan2 (static_cast <basis_type>(-1.0 ), static_cast <basis_type>(2.0 ))});
66+ const auto a {opaque (static_cast <basis_type>(1.0 ))};
67+ const auto b {opaque (static_cast <basis_type>(1.0 ))};
68+ BOOST_TEST (atan2 (T{a}, T{b}) == T{std::atan2 (a, b)});
69+ const auto c {opaque (static_cast <basis_type>(-1.0 ))};
70+ const auto d {opaque (static_cast <basis_type>(2.0 ))};
71+ BOOST_TEST (atan2 (T{c}, T{d}) == T{std::atan2 (c, d)});
5772}
5873
5974// asin/acos outside [-1, 1] produce NAN -> domain_error
0 commit comments