Home | Libraries | People | FAQ | More |
As noted in the Boost.Multiprecision documentation, certain program constructs will not compile when using expression templates. One example that many users may encounter is Boost.Test (1.54 and earlier) when using macro BOOST_CHECK_CLOSE and BOOST_CHECK_CLOSE_FRACTION.
If, for example, you wish to use any multiprecision type like cpp_dec_float_50
in place of double
to give more precision, you will need
to override the default boost::multiprecision::et_on
with boost::multiprecision::et_off
.
#include <boost/multiprecision/cpp_dec_float.hpp>
To define a 50 decimal digit type using cpp_dec_float
,
you must pass two template parameters to boost::multiprecision::number
.
It may be more legible to use a two-staged type definition such as this:
typedef boost::multiprecision::cpp_dec_float<50> mp_backend; typedef boost::multiprecision::number<mp_backend, boost::multiprecision::et_off> cpp_dec_float_50_noet;
Here, we first define mp_backend
as cpp_dec_float
with 50
digits. The second step passes this backend to boost::multiprecision::number
with boost::multiprecision::et_off
, an enumerated type.
typedef boost::multiprecision::number<boost::multiprecision::cpp_dec_float<50>, boost::multiprecision::et_off> cpp_dec_float_50_noet;
You can reduce typing with a using
directive using namespace
boost::multiprecision;
if desired, as shown below.
using namespace boost::multiprecision;
Now cpp_dec_float_50_noet
or cpp_dec_float_50_et
can
be used as a direct replacement for built-in types like double
etc.
BOOST_AUTO_TEST_CASE(cpp_float_test_check_close_noet) { // No expression templates/ typedef number<cpp_dec_float<50>, et_off> cpp_dec_float_50_noet; std::cout.precision(std::numeric_limits<cpp_dec_float_50_noet>::digits10); // All significant digits. std::cout << std::showpoint << std::endl; // Show trailing zeros. cpp_dec_float_50_noet a ("1.0"); cpp_dec_float_50_noet b ("1.0"); b += std::numeric_limits<cpp_dec_float_50_noet>::epsilon(); // Increment least significant decimal digit. cpp_dec_float_50_noet eps = std::numeric_limits<cpp_dec_float_50_noet>::epsilon(); std::cout <<"a = " << a << ",\nb = " << b << ",\neps = " << eps << std::endl; BOOST_CHECK_CLOSE(a, b, eps * 100); // Expected to pass (because tolerance is as percent). BOOST_CHECK_CLOSE_FRACTION(a, b, eps); // Expected to pass (because tolerance is as fraction). } // BOOST_AUTO_TEST_CASE(cpp_float_test_check_close) BOOST_AUTO_TEST_CASE(cpp_float_test_check_close_et) { // Using expression templates. typedef number<cpp_dec_float<50>, et_on> cpp_dec_float_50_et; std::cout.precision(std::numeric_limits<cpp_dec_float_50_et>::digits10); // All significant digits. std::cout << std::showpoint << std::endl; // Show trailing zeros. cpp_dec_float_50_et a("1.0"); cpp_dec_float_50_et b("1.0"); b += std::numeric_limits<cpp_dec_float_50_et>::epsilon(); // Increment least significant decimal digit. cpp_dec_float_50_et eps = std::numeric_limits<cpp_dec_float_50_et>::epsilon(); std::cout << "a = " << a << ",\nb = " << b << ",\neps = " << eps << std::endl; BOOST_CHECK_CLOSE(a, b, eps * 100); // Expected to pass (because tolerance is as percent). BOOST_CHECK_CLOSE_FRACTION(a, b, eps); // Expected to pass (because tolerance is as fraction).
Using cpp_dec_float_50
with
the default expression template use switched on, the compiler error message
for `BOOST_CHECK_CLOSE_FRACTION(a, b, eps); would be:
// failure floating_point_comparison.hpp(59): error C2440: 'static_cast' : // cannot convert from 'int' to 'boost::multiprecision::detail::expression<tag,Arg1,Arg2,Arg3,Arg4>'
A full example code is at test_cpp_float_close_fraction.cpp