From eb2707e8b0989a6ebcdbd58f77aed6c37db911c2 Mon Sep 17 00:00:00 2001 From: pabristow Date: Mon, 2 Jan 2017 18:31:16 +0000 Subject: [PATCH] Failed attempts to get create_test_value to work. --- example/lambert_w_diode_graph.cpp | 11 +-- test/test_lambert_w.cpp | 110 +++++++++++++++++++----------- 2 files changed, 77 insertions(+), 44 deletions(-) diff --git a/example/lambert_w_diode_graph.cpp b/example/lambert_w_diode_graph.cpp index e75ab70cb..df6c5a8e2 100644 --- a/example/lambert_w_diode_graph.cpp +++ b/example/lambert_w_diode_graph.cpp @@ -5,8 +5,9 @@ // (See accompanying file LICENSE_1_0.txt or // copy at http ://www.boost.org/LICENSE_1_0.txt). -/*! \brief Graph of using Lambert W function to compute current +/*! \brief Graph showing use of Lambert W function to compute current through a diode-connected transistor with preset series resistance. + \details T. C. Banwell and A. Jayakumar, Exact analytical solution of current flow through diode with series resistance, Electron Letters, 36(4):291-2 (2000) @@ -24,7 +25,6 @@ The solid curves in Figure 2 are calculated using equation 5 with rsat included http://www3.imperial.ac.uk/pls/portallive/docs/1/7292572.PDF - */ #include @@ -223,7 +223,7 @@ int main() data_plot.title("Diode current versus voltage") .x_size(400) .y_size(300) - //.legend_on(false) + .legend_on(true) .x_label("voltage (V)") .y_label("log(current)") //.x_label_on(true) @@ -239,8 +239,9 @@ int main() //.y_values_on(true) .y_values_rotation(horizontal) //.plot_window_on(true) - .x_values_precision(4) - .y_values_precision(5) + .x_values_precision(3) + .y_values_precision(3) + .coord_precision(4) // Needed to avoid stepping on curves. .copyright_holder("Paul A. Bristow") .copyright_date("2016") //.background_border_color(black); diff --git a/test/test_lambert_w.cpp b/test/test_lambert_w.cpp index 07d2563bb..fec9f993a 100644 --- a/test/test_lambert_w.cpp +++ b/test/test_lambert_w.cpp @@ -36,29 +36,43 @@ using boost::multiprecision::cpp_dec_float_50; #include // 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 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(val); +} + +template +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(val); } template 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 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(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(\ x##L,\ #x,\ boost::mpl::bool_<\ std::numeric_limits::is_specialized &&\ - (std::numeric_limits::radix == 2) && (std::numeric_limits::digits\ - <= std::numeric_limits::digits) && boost::is_convertible::value>(),\ + (std::numeric_limits::radix == 2)\ + && (std::numeric_limits::digits <= std::numeric_limits::digits)\ + && boost::is_convertible::value>(),\ boost::mpl::bool_<\ boost::is_constructible::value>()\ ) @@ -85,17 +106,27 @@ inline T create_test_value(long double, const char* str, const boost::mpl::false template 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::is_specialized - << " digits " << std::numeric_limits::digits // binary digits 24 - << ", is_convertible " << boost::is_convertible::value << std::endl // convertible to string - << " is_constructible " << boost::is_constructible::value // constructible from string - << std::endl; + << ", radix = " << std::numeric_limits::radix + << ", digits = " << std::numeric_limits::digits // binary digits, 24 for float, 53 for double ... + << ", is_convertible " << boost::is_convertible::value // is convertible long double *to* T. + << ", is_constructible " << boost::is_constructible::value // is constructible *from* string. + << std::endl; + + std::cout << " T1 = " + << ( + (std::numeric_limits::is_specialized) + && (std::numeric_limits::radix == 2) + && (std::numeric_limits::digits <= std::numeric_limits::digits) + && (boost::is_convertible::value) + ) + << ", T2 = " << (boost::is_constructible::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 test_data = @@ -106,16 +137,12 @@ static const boost::array test_data = //static const boost::array 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(0, -1), std::domain_error); // negative sd //#endif + using boost::math::productlog; + using boost::math::constants::expminusone; RealType tolerance = boost::math::tools::epsilon() * 5; // 5 eps as a fraction. std::cout << "Testing type " << typeid(RealType).name() << std::endl; @@ -145,27 +174,30 @@ void test_spots(RealType) show(); - using boost::math::productlog; + std::cout << " Create type: " + << ((create_type ==1) ? "create from static_cast(val) " : + (create_type == 2) ? "construct from T(str)" : + (create_type == 3) ? "boost::lexical_cast(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 ::max_digits10); - test_value = -boost::math::constants::expminusone(); - 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(); // -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)