2
0
mirror of https://github.com/boostorg/math.git synced 2026-02-14 12:52:15 +00:00

Failed attempts to get create_test_value to work.

This commit is contained in:
pabristow
2017-01-02 18:31:16 +00:00
parent ffb025ca2c
commit eb2707e8b0
2 changed files with 77 additions and 44 deletions

View File

@@ -36,29 +36,43 @@ using boost::multiprecision::cpp_dec_float_50;
#include <type_traits>
// BOOST_MATH_TEST_VALUE is used to create a test value of suitable type from a decimal digit string.
// Two parameters, both a literal like 1.23 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.
// * It's slow to compile compared to a simple literal - not an issue for a
// few test values, but it's not generally usable in large tables
// * It's slow to compile compared to a simple literal.
// This 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.
int create_type(0);
template <class T, class T1, class T2>
inline T create_test_value(long double val, const char*, const T1&, const T2&)
{ // Construct from long double parameter val (ignoring string/const char*)
{ // Construct from long double parameter val (ignoring string/const char* str)
create_type = 1;
return static_cast<T>(val);
}
template <class T, class T1, class T2>
inline T create_test_value(long double val, const char*, const boost::mpl::true_&, const boost::mpl::false_&)
{ // Construct from long double parameter val (ignoring string/const char* str)
create_type = 1;
return static_cast<T>(val);
}
template <class T>
inline T create_test_value(long double, const char* str, const boost::mpl::false_&, const boost::mpl::true_&)
{ // Construct from string (ignoring long double parameter).
{ // Construct from decimal digit string const char* @c str (ignoring long double parameter).
create_type = 2;
return T(str);
}
template <class T>
inline T create_test_value(long double, const char* str, const boost::mpl::false_&, const boost::mpl::false_&)
{ // Create test value using from lexical cast of string.
{ // Create test value using from lexical cast of decimal digit string const char* str.
create_type = 3;
return boost::lexical_cast<T>(str);
}
@@ -66,18 +80,25 @@ inline T create_test_value(long double, const char* str, const boost::mpl::false
// x is converted to a long double by appending the letter L (to suit long double fundamental type)
// x is also passed as a const char* or string representation
// (to suit most other types that cannot be constructed from long double without loss)
// (to suit most other types that cannot be constructed from long double without possible loss).
// x##L makes a long double version, suffix a letter L to suit long double fundamental type.
// #x makes a decimal digit string version to suit multiprecision and fixed_point constructors.
// (Constructing from double or long double 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(long double, 9.);
// x##L is a long double version, suffix a letter L to suit long double fundamental type.
// #x is a string version to suit multiprecision constructors
// (constructing from double or long double would loose precision).
#define BOOST_MATH_TEST_VALUE(T, x) create_test_value<T>(\
x##L,\
#x,\
boost::mpl::bool_<\
std::numeric_limits<T>::is_specialized &&\
(std::numeric_limits<T>::radix == 2) && (std::numeric_limits<T>::digits\
<= std::numeric_limits<long double>::digits) && boost::is_convertible<long double, T>::value>(),\
(std::numeric_limits<T>::radix == 2)\
&& (std::numeric_limits<T>::digits <= std::numeric_limits<long double>::digits)\
&& boost::is_convertible<long double, T>::value>(),\
boost::mpl::bool_<\
boost::is_constructible<T, const char*>::value>()\
)
@@ -85,17 +106,27 @@ inline T create_test_value(long double, const char* str, const boost::mpl::false
template <class T>
void show()
{
std::cout << std::boolalpha << typeid(T).name() << std::endl
std::cout << std::boolalpha << "Test with type:\n"
<< typeid(T).name() << std::endl
<< " is specialized " << std::numeric_limits<T>::is_specialized
<< " digits " << std::numeric_limits<T>::digits // binary digits 24
<< ", is_convertible " << boost::is_convertible<T, const char*>::value << std::endl // convertible to string
<< " is_constructible " << boost::is_constructible<T, const char*>::value // constructible from string
<< std::endl;
<< ", radix = " << std::numeric_limits<T>::radix
<< ", digits = " << std::numeric_limits<T>::digits // binary digits, 24 for float, 53 for double ...
<< ", is_convertible " << boost::is_convertible<long double, T>::value // is convertible long double *to* T.
<< ", is_constructible " << boost::is_constructible<T, const char*>::value // is constructible *from* string.
<< std::endl;
std::cout << " T1 = "
<< (
(std::numeric_limits<T>::is_specialized)
&& (std::numeric_limits<T>::radix == 2)
&& (std::numeric_limits<T>::digits <= std::numeric_limits<long double>::digits)
&& (boost::is_convertible<long double, T>::value)
)
<< ", T2 = " << (boost::is_constructible<T, const char*>::value)
<< std::endl;
} // show
long double test_value = BOOST_MATH_TEST_VALUE(long double, 1.);
static const unsigned int noof_tests = 2;
static const boost::array<const char*, noof_tests> test_data =
@@ -106,16 +137,12 @@ static const boost::array<const char*, noof_tests> test_data =
//static const boost::array<const char*, noof_tests> test_expected =
//{ {
// BOOST_MATH_TEST_VALUE("0.56714329040978387299996866221035554975381578718651"), // Output from https://www.wolframalpha.com/input/?i=productlog(1)
// BOOST_MATH_TEST_VALUE("1.432404775898300311234078007212058694786434608804302025655") // Output from https://www.wolframalpha.com/input/?i=productlog(6)
// BOOST_MATH_TEST_VALUE(T, 0.56714329040978387299996866221035554975381578718651), // Output from https://www.wolframalpha.com/input/?i=productlog(1)
// BOOST_MATH_TEST_VALUE(T, 1.432404775898300311234078007212058694786434608804302025655) // Output from https://www.wolframalpha.com/input/?i=productlog(6)
// } }; // array test_data
//BOOST_MATH_TEST_VALUE("-0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527")
// w(-0.367879441171442321595523770161460867445811131031767834)
//
// ProductLog[-0.367879441171442321595523770161460867445811131031767834]
@@ -134,6 +161,8 @@ void test_spots(RealType)
// BOOST_MATH_CHECK_THROW(boost::math::normal_distribution<RealType>(0, -1), std::domain_error); // negative sd
//#endif
using boost::math::productlog;
using boost::math::constants::expminusone;
RealType tolerance = boost::math::tools::epsilon<RealType>() * 5; // 5 eps as a fraction.
std::cout << "Testing type " << typeid(RealType).name() << std::endl;
@@ -145,27 +174,30 @@ void test_spots(RealType)
show<RealType>();
using boost::math::productlog;
std::cout << " Create type: "
<< ((create_type ==1) ? "create from static_cast<T>(val) " :
(create_type == 2) ? "construct from T(str)" :
(create_type == 3) ? "boost::lexical_cast<T>(str)" :
"???") // ??? create_type == 0 should never happen?
<< std::endl;
RealType test_value = BOOST_MATH_TEST_VALUE(RealType, 1.);
RealType expected_value = BOOST_MATH_TEST_VALUE(RealType, 0.56714329040978387299996866221035554975381578718651);
test_value = BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176);
expected_value = BOOST_MATH_TEST_VALUE(RealType, -1.);
std::cout.precision(std::numeric_limits <RealType>::max_digits10);
test_value = -boost::math::constants::expminusone<RealType>();
std::cout << "test " << test_value << ", expected " << expected_value << std::endl;
BOOST_CHECK_CLOSE_FRACTION(
RealType test_value = BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176);
RealType expected_value = BOOST_MATH_TEST_VALUE(RealType, -1.);
test_value = -boost::math::constants::expminusone<RealType>(); // -exp(-1) = -0.367879450
std::cout << "test " << test_value << ", expected productlog = " << expected_value << std::endl;
BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) = -0.367879450 = -1
productlog(test_value),
expected_value,
tolerance); // OK
// This fails for reasons unclear (apparently identical test above passes)???
//BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) = -0.367879450 = -1
// productlog(BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176)),
// BOOST_MATH_TEST_VALUE(RealType, -1.),
// tolerance);
BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) = -0.367879450 = -1
productlog(BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176)),
BOOST_MATH_TEST_VALUE(RealType, -1.),
tolerance);
BOOST_CHECK_CLOSE_FRACTION(
productlog(BOOST_MATH_TEST_VALUE(RealType, 1.)),
@@ -210,7 +242,7 @@ void test_spots(RealType)
// Output from https://www.wolframalpha.com/input/?i=productlog(100)
tolerance);
// Fails here with really big x.
// TODO Fails here with really big x.
/* BOOST_CHECK_CLOSE_FRACTION(productlog(BOOST_MATH_TEST_VALUE(RealType, 1.0e6)),
BOOST_MATH_TEST_VALUE(RealType, 11.383358086140052622000156781585004289033774706019),
// Output from https://www.wolframalpha.com/input/?i=productlog(1e6)