summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/math/test/test_lambert_w_integrals_float128.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/math/test/test_lambert_w_integrals_float128.cpp')
-rw-r--r--src/boost/libs/math/test/test_lambert_w_integrals_float128.cpp276
1 files changed, 276 insertions, 0 deletions
diff --git a/src/boost/libs/math/test/test_lambert_w_integrals_float128.cpp b/src/boost/libs/math/test/test_lambert_w_integrals_float128.cpp
new file mode 100644
index 000000000..e83a57ddc
--- /dev/null
+++ b/src/boost/libs/math/test/test_lambert_w_integrals_float128.cpp
@@ -0,0 +1,276 @@
+// Copyright Paul A. Bristow 2016, 2017, 2018.
+// Copyright John Maddock 2016.
+
+// 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_lambert_w_integrals.cpp
+//! \brief quadrature tests that cover the whole range of the Lambert W0 function.
+
+#include <boost/config.hpp> // for BOOST_MSVC definition etc.
+#include <boost/version.hpp> // for BOOST_MSVC versions.
+
+#ifdef BOOST_HAS_FLOAT128
+
+// Boost macros
+#define BOOST_TEST_MAIN
+#define BOOST_LIB_DIAGNOSTIC "on" // Report library file details.
+#include <boost/test/included/unit_test.hpp> // Boost.Test
+#include <boost/test/tools/floating_point_comparison.hpp>
+
+#include <boost/array.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/type_traits/is_constructible.hpp>
+
+#include <boost/multiprecision/float128.hpp>
+
+#include <boost/math/special_functions/fpclassify.hpp> // isnan, isfinite.
+#include <boost/math/special_functions/next.hpp> // float_next, float_prior
+using boost::math::float_next;
+using boost::math::float_prior;
+#include <boost/math/special_functions/ulp.hpp> // ulp
+
+#include <boost/math/tools/test_value.hpp> // for create_test_value and macro BOOST_MATH_TEST_VALUE.
+#include <boost/math/policies/policy.hpp>
+using boost::math::policies::digits2;
+using boost::math::policies::digits10;
+#include <boost/math/special_functions/lambert_w.hpp> // For Lambert W lambert_w function.
+using boost::math::lambert_wm1;
+using boost::math::lambert_w0;
+
+#include <limits>
+#include <cmath>
+#include <typeinfo>
+#include <iostream>
+#include <type_traits>
+#include <exception>
+
+std::string show_versions(void);
+
+// Added code and test for Integral of the Lambert W function: by Nick Thompson.
+// https://en.wikipedia.org/wiki/Lambert_W_function#Definite_integrals
+
+#include <boost/math/constants/constants.hpp> // for integral tests.
+#include <boost/math/quadrature/tanh_sinh.hpp> // for integral tests.
+#include <boost/math/quadrature/exp_sinh.hpp> // for integral tests.
+
+ using boost::math::policies::policy;
+ using boost::math::policies::make_policy;
+
+// using statements needed for changing error handling policy.
+using boost::math::policies::evaluation_error;
+using boost::math::policies::domain_error;
+using boost::math::policies::overflow_error;
+using boost::math::policies::ignore_error;
+using boost::math::policies::throw_on_error;
+
+typedef policy<
+ domain_error<throw_on_error>,
+ overflow_error<ignore_error>
+> no_throw_policy;
+
+// Assumes that function has a throw policy, for example:
+// NOT lambert_w0<T>(1 / (x * x), no_throw_policy());
+// Error in function boost::math::quadrature::exp_sinh<double>::integrate:
+// The exp_sinh quadrature evaluated your function at a singular point and resulted in inf.
+// Please ensure your function evaluates to a finite number of its entire domain.
+template <typename T>
+T debug_integration_proc(T x)
+{
+ T result; // warning C4701: potentially uninitialized local variable 'result' used
+ // T result = 0 ; // But result may not be assigned below?
+ try
+ {
+ // Assign function call to result in here...
+ if (x <= sqrt(boost::math::tools::min_value<T>()) )
+ {
+ result = 0;
+ }
+ else
+ {
+ result = lambert_w0<T>(1 / (x * x));
+ }
+ // result = lambert_w0<T>(1 / (x * x), no_throw_policy()); // Bad idea, less helpful diagnostic message is:
+ // Error in function boost::math::quadrature::exp_sinh<double>::integrate:
+ // The exp_sinh quadrature evaluated your function at a singular point and resulted in inf.
+ // Please ensure your function evaluates to a finite number of its entire domain.
+
+ } // try
+ catch (const std::exception& e)
+ {
+ std::cout << "Exception " << e.what() << std::endl;
+ // set breakpoint here:
+ std::cout << "Unexpected exception thrown in integration code at abscissa (x): " << x << "." << std::endl;
+ if (!std::isfinite(result))
+ {
+ // set breakpoint here:
+ std::cout << "Unexpected non-finite result in integration code at abscissa (x): " << x << "." << std::endl;
+ }
+ if (std::isnan(result))
+ {
+ // set breakpoint here:
+ std::cout << "Unexpected non-finite result in integration code at abscissa (x): " << x << "." << std::endl;
+ }
+ } // catch
+ return result;
+} // T debug_integration_proc(T x)
+
+template<class Real>
+void test_integrals()
+{
+ // Integral of the Lambert W function:
+ // https://en.wikipedia.org/wiki/Lambert_W_function
+ using boost::math::quadrature::tanh_sinh;
+ using boost::math::quadrature::exp_sinh;
+ // file:///I:/modular-boost/libs/math/doc/html/math_toolkit/quadrature/double_exponential/de_tanh_sinh.html
+ using std::sqrt;
+
+ std::cout << "Integration of type " << typeid(Real).name() << std::endl;
+
+ Real tol = std::numeric_limits<Real>::epsilon();
+ { // // Integrate for function lambert_W0(z);
+ tanh_sinh<Real> ts;
+ Real a = 0;
+ Real b = boost::math::constants::e<Real>();
+ auto f = [](Real z)->Real
+ {
+ return lambert_w0<Real>(z);
+ };
+ Real z = ts.integrate(f, a, b); // OK without any decltype(f)
+ BOOST_CHECK_CLOSE_FRACTION(z, boost::math::constants::e<Real>() - 1, tol);
+ }
+ {
+ // Integrate for function lambert_W0(z/(z sqrt(z)).
+ exp_sinh<Real> es;
+ auto f = [](Real z)->Real
+ {
+ return lambert_w0<Real>(z)/(z * sqrt(z));
+ };
+ Real z = es.integrate(f); // OK
+ BOOST_CHECK_CLOSE_FRACTION(z, 2 * boost::math::constants::root_two_pi<Real>(), tol);
+ }
+ {
+ // Integrate for function lambert_W0(1/z^2).
+ exp_sinh<Real> es;
+ //const Real sqrt_min = sqrt(boost::math::tools::min_value<Real>()); // 1.08420217e-19 fo 32-bit float.
+ // error C3493: 'sqrt_min' cannot be implicitly captured because no default capture mode has been specified
+ auto f = [](Real z)->Real
+ {
+ if (z <= sqrt(boost::math::tools::min_value<Real>()) )
+ { // Too small would underflow z * z and divide by zero to overflow 1/z^2 for lambert_w0 z parameter.
+ return static_cast<Real>(0);
+ }
+ else
+ {
+ return lambert_w0<Real>(1 / (z * z)); // warning C4756: overflow in constant arithmetic, even though cannot happen.
+ }
+ };
+ Real z = es.integrate(f);
+ BOOST_CHECK_CLOSE_FRACTION(z, boost::math::constants::root_two_pi<Real>(), tol);
+ }
+} // template<class Real> void test_integrals()
+
+
+BOOST_AUTO_TEST_CASE( integrals )
+{
+ std::cout << "Macro BOOST_MATH_LAMBERT_W0_INTEGRALS is defined." << std::endl;
+ BOOST_TEST_MESSAGE("\nTest Lambert W0 integrals.");
+ try
+ {
+ // using statements needed to change precision policy.
+ using boost::math::policies::policy;
+ using boost::math::policies::make_policy;
+ using boost::math::policies::precision;
+ using boost::math::policies::digits2;
+ using boost::math::policies::digits10;
+
+ // using statements needed for changing error handling policy.
+ using boost::math::policies::evaluation_error;
+ using boost::math::policies::domain_error;
+ using boost::math::policies::overflow_error;
+ using boost::math::policies::ignore_error;
+ using boost::math::policies::throw_on_error;
+
+ /*
+ typedef policy<
+ domain_error<throw_on_error>,
+ overflow_error<ignore_error>
+ > no_throw_policy;
+
+
+ // Experiment with better diagnostics.
+ typedef float Real;
+
+ Real inf = std::numeric_limits<Real>::infinity();
+ Real max = (std::numeric_limits<Real>::max)();
+ std::cout.precision(std::numeric_limits<Real>::max_digits10);
+ //std::cout << "lambert_w0(inf) = " << lambert_w0(inf) << std::endl; // lambert_w0(inf) = 1.79769e+308
+ std::cout << "lambert_w0(inf, throw_policy()) = " << lambert_w0(inf, no_throw_policy()) << std::endl; // inf
+ std::cout << "lambert_w0(max) = " << lambert_w0(max) << std::endl; // lambert_w0(max) = 703.227
+ //std::cout << lambert_w0(inf) << std::endl; // inf - will throw.
+ std::cout << "lambert_w0(0) = " << lambert_w0(0.) << std::endl; // 0
+ std::cout << "lambert_w0(std::numeric_limits<Real>::denorm_min()) = " << lambert_w0(std::numeric_limits<Real>::denorm_min()) << std::endl; // 4.94066e-324
+ std::cout << "lambert_w0(std::numeric_limits<Real>::min()) = " << lambert_w0((std::numeric_limits<Real>::min)()) << std::endl; // 2.22507e-308
+
+ // Approximate the largest lambert_w you can get for type T?
+ float max_w_f = boost::math::lambert_w_detail::lambert_w0_approx((std::numeric_limits<float>::max)()); // Corless equation 4.19, page 349, and Chapeau-Blondeau equation 20, page 2162.
+ std::cout << "w max_f " << max_w_f << std::endl; // 84.2879
+ Real max_w = boost::math::lambert_w_detail::lambert_w0_approx((std::numeric_limits<Real>::max)()); // Corless equation 4.19, page 349, and Chapeau-Blondeau equation 20, page 2162.
+ std::cout << "w max " << max_w << std::endl; // 703.227
+
+ std::cout << "lambert_w0(7.2416706213544837e-163) = " << lambert_w0(7.2416706213544837e-163) << std::endl; //
+ std::cout << "test integral 1/z^2" << std::endl;
+ std::cout << "ULP = " << boost::math::ulp(1., policy<digits2<> >()) << std::endl; // ULP = 2.2204460492503131e-16
+ std::cout << "ULP = " << boost::math::ulp(1e-10, policy<digits2<> >()) << std::endl; // ULP = 2.2204460492503131e-16
+ std::cout << "ULP = " << boost::math::ulp(1., policy<digits2<11> >()) << std::endl; // ULP = 2.2204460492503131e-16
+ std::cout << "epsilon = " << std::numeric_limits<Real>::epsilon() << std::endl; //
+ std::cout << "sqrt(max) = " << sqrt(boost::math::tools::max_value<float>() ) << std::endl; // sqrt(max) = 1.8446742974197924e+19
+ std::cout << "sqrt(min) = " << sqrt(boost::math::tools::min_value<float>() ) << std::endl; // sqrt(min) = 1.0842021724855044e-19
+
+
+
+// Demo debug version.
+Real tol = std::numeric_limits<Real>::epsilon();
+Real x;
+{
+ using boost::math::quadrature::exp_sinh;
+ exp_sinh<Real> es;
+ // Function to be integrated, lambert_w0(1/z^2).
+
+ //auto f = [](Real z)->Real
+ //{ // Naive - no protection against underflow and subsequent divide by zero.
+ // return lambert_w0<Real>(1 / (z * z));
+ //};
+ // Diagnostic is:
+ // Error in function boost::math::lambert_w0<Real>: Expected a finite value but got inf
+
+ auto f = [](Real z)->Real
+ { // Debug with diagnostics for underflow and subsequent divide by zero and other bad things.
+ return debug_integration_proc(z);
+ };
+ // Exception Error in function boost::math::lambert_w0<double>: Expected a finite value but got inf.
+
+ // Unexpected exception thrown in integration code at abscissa: 7.2416706213544837e-163.
+ // Unexpected exception thrown in integration code at abscissa (x): 3.478765835953569e-23.
+ x = es.integrate(f);
+ std::cout << "es.integrate(f) = " << x << std::endl;
+ BOOST_CHECK_CLOSE_FRACTION(x, boost::math::constants::root_two_pi<Real>(), tol);
+ // root_two_pi<double = 2.506628274631000502
+ }
+ */
+
+ test_integrals<boost::multiprecision::float128>();
+ }
+ catch (std::exception& ex)
+ {
+ std::cout << ex.what() << std::endl;
+ }
+}
+
+#else
+
+int main() { return 0; }
+
+#endif