// Use, modification and distribution are subject to the // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // Copyright Paul A. Bristow 2013 // Copyright Christopher Kormanyos 2013. // Copyright John Maddock 2013. #ifdef _MSC_VER # pragma warning (disable : 4512) # pragma warning (disable : 4996) #endif #define BOOST_TEST_MAIN #define BOOST_LIB_DIAGNOSTIC "on"// Show library file details. //[expression_template_1 #include <limits> #include <iostream> #include <boost/multiprecision/cpp_dec_float.hpp> #include <boost/test/tools/floating_point_comparison.hpp> // Extra test tool for FP comparison. #include <boost/test/unit_test.hpp> typedef boost::multiprecision::number< boost::multiprecision::cpp_dec_float<50>, boost::multiprecision::et_off> cpp_dec_float_50_noet; typedef boost::multiprecision::number< boost::multiprecision::cpp_dec_float<50>, boost::multiprecision::et_on> cpp_dec_float_50_et; // there is no need for this anymore, however this could be defined by // the user in order to support additional types for floating point // comparison. #if 0 namespace boost { namespace math { namespace fpc { template <class A, boost::multiprecision::expression_template_option B> struct tolerance_based< boost::multiprecision::number< A, B > > : boost::mpl::true_ {}; template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> struct tolerance_based< boost::multiprecision::detail::expression< tag, Arg1, Arg2, Arg3, Arg4> > : boost::mpl::true_ {}; } } } #endif /*`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; #if 0 BOOST_AUTO_TEST_CASE(multiprecision_types_are_arithmetic) { typedef number<cpp_dec_float<50>, et_off> cpp_dec_float_50_noet; BOOST_TEST((std::numeric_limits<cpp_dec_float_50_noet>::is_specialized)); } #endif /*`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). #ifndef BOOST_TEST_MACRO_LIMITED_SUPPORT namespace tt = boost::test_tools; BOOST_TEST( a == b, tt::tolerance( tt::fpc::percent_tolerance( eps * 100 ) ) ); BOOST_TEST( a == b, tt::tolerance( eps ) ); #endif //] [/expression_template_1]git } // 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). #ifndef BOOST_TEST_MACRO_LIMITED_SUPPORT namespace tt = boost::test_tools; BOOST_TEST( a == b, tt::tolerance( tt::fpc::percent_tolerance<cpp_dec_float_50_et>( eps * 100 ) ) ); BOOST_TEST( a == b, tt::tolerance( eps ) ); #endif /*`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>' //] [/expression_template_1] } // BOOST_AUTO_TEST_CASE(cpp_float_test_check_close) /* Output: Description: Autorun "J:\Cpp\big_number\Debug\test_cpp_float_close_fraction.exe" Running 1 test case... a = 1.0000000000000000000000000000000000000000000000000, b = 1.0000000000000000000000000000000000000000000000001, eps = 1.0000000000000000000000000000000000000000000000000e-49 *** No errors detected */