diff options
Diffstat (limited to 'boost/math/tools/test_value.hpp')
-rw-r--r-- | boost/math/tools/test_value.hpp | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/boost/math/tools/test_value.hpp b/boost/math/tools/test_value.hpp new file mode 100644 index 0000000000..e597f2ad48 --- /dev/null +++ b/boost/math/tools/test_value.hpp @@ -0,0 +1,118 @@ +// Copyright Paul A. Bristow 2017. +// Copyright John Maddock 2017. + +// 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) + +// test_value.hpp + +#ifndef TEST_VALUE_HPP +#define TEST_VALUE_HPP + +// BOOST_MATH_TEST_VALUE is used to create a test value of suitable type from a decimal digit string. +// Two parameters, both a floating-point literal double like 1.23 (not long double so no suffix L) +// and a decimal digit string const char* like "1.23" must be provided. +// The decimal value represented must be the same of course, with at least enough precision for long double. +// Note there are two gotchas to this approach: +// * You need all values to be real floating-point values +// * and *MUST* include a decimal point (to avoid confusion with an integer literal). +// * It's slow to compile compared to a simple literal. + +// Speed is not an issue for a few test values, +// but it's not generally usable in large tables +// where you really need everything to be statically initialized. + +// Macro BOOST_MATH_INSTRUMENT_CREATE_TEST_VALUE provides a global diagnostic value for create_type. + +#include <boost/cstdfloat.hpp> // For float_64_t, float128_t. Must be first include! +#include <boost/lexical_cast.hpp> +#include <boost/type_traits/is_constructible.hpp> +#include <boost/type_traits/is_convertible.hpp> + +#ifdef BOOST_MATH_INSTRUMENT_CREATE_TEST_VALUE +// global int create_type(0); must be defined before including this file. +#endif + +#ifdef BOOST_HAS_FLOAT128 +typedef __float128 largest_float; +#define BOOST_MATH_TEST_LARGEST_FLOAT_SUFFIX(x) x##Q +#define BOOST_MATH_TEST_LARGEST_FLOAT_DIGITS 113 +#else +typedef long double largest_float; +#define BOOST_MATH_TEST_LARGEST_FLOAT_SUFFIX(x) x##L +#define BOOST_MATH_TEST_LARGEST_FLOAT_DIGITS std::numeric_limits<long double>::digits +#endif + +template <class T, class T2> +inline T create_test_value(largest_float val, const char*, const boost::mpl::true_&, const T2&) +{ // Construct from long double or quad parameter val (ignoring string/const char* str). + // (This is case for MPL parameters = true_ and T2 == false_, + // and MPL parameters = true_ and T2 == true_ cpp_bin_float) + // All built-in/fundamental floating-point types, + // and other User-Defined Types that can be constructed without loss of precision + // from long double suffix L (or quad suffix Q), + // + // Choose this method, even if can be constructed from a string, + // because it will be faster, and more likely to be the closest representation. + // (This is case for MPL parameters = mpl::true_ and T2 == mpl::true_). + #ifdef BOOST_MATH_INSTRUMENT_CREATE_TEST_VALUE + create_type = 1; + #endif + return static_cast<T>(val); +} + +template <class T> +inline T create_test_value(largest_float, const char* str, const boost::mpl::false_&, const boost::mpl::true_&) +{ // Construct from decimal digit string const char* @c str (ignoring long double parameter). + // For example, extended precision or other User-Defined types which ARE constructible from a string + // (but not from double, or long double without loss of precision). + // (This is case for MPL parameters = mpl::false_ and T2 == mpl::true_). + #ifdef BOOST_MATH_INSTRUMENT_CREATE_TEST_VALUE + create_type = 2; + #endif + return T(str); +} + +template <class T> +inline T create_test_value(largest_float, const char* str, const boost::mpl::false_&, const boost::mpl::false_&) +{ // Create test value using from lexical cast of decimal digit string const char* str. + // For example, extended precision or other User-Defined types which are NOT constructible from a string + // (NOR constructible from a long double). + // (This is case T1 = mpl::false and T2 == mpl::false). + #ifdef BOOST_MATH_INSTRUMENT_CREATE_TEST_VALUE + create_type = 3; + #endif + return boost::lexical_cast<T>(str); +} + +// T real type, x a decimal digits representation of a floating-point, for example: 12.34. +// It must include a decimal point (or it would be interpreted as an integer). + +// x is converted to a long double by appending the letter L (to suit long double fundamental type), 12.34L. +// x is also passed as a const char* or string representation "12.34" +// (to suit most other types that cannot be constructed from long double without possible loss). + +// BOOST_MATH_TEST_LARGEST_FLOAT_SUFFIX(x) makes a long double or quad version, with +// suffix a letter L (or Q) to suit long double (or quad) fundamental type, 12.34L or 12.34Q. +// #x makes a decimal digit string version to suit multiprecision and fixed_point constructors, "12.34". +// (Constructing from double or long double (or quad) could lose precision for multiprecision or fixed-point). + +// The matching create_test_value function above is chosen depending on the T1 and T2 mpl bool truths. +// The string version from #x is used if the precision of T is greater than long double. + +// Example: long double test_value = BOOST_MATH_TEST_VALUE(double, 1.23456789); + +#define BOOST_MATH_TEST_VALUE(T, x) create_test_value<T>(\ + BOOST_MATH_TEST_LARGEST_FLOAT_SUFFIX(x),\ + #x,\ + boost::mpl::bool_<\ + std::numeric_limits<T>::is_specialized &&\ + (std::numeric_limits<T>::radix == 2)\ + && (std::numeric_limits<T>::digits <= BOOST_MATH_TEST_LARGEST_FLOAT_DIGITS)\ + && boost::is_convertible<largest_float, T>::value>(),\ + boost::mpl::bool_<\ + boost::is_constructible<T, const char*>::value>()\ +) +#endif // TEST_VALUE_HPP |