1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
|
// Copyright Paul A. Bristow 2016, 2017.
// Distributed under 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).
// Build and run a simple examples of Lambert W function.
// Some macros that will show some(or much) diagnostic values if #defined.
//#define-able macros
//#define BOOST_MATH_INSTRUMENT_LAMBERT_W0 // W0 branch diagnostics.
//#define BOOST_MATH_INSTRUMENT_LAMBERT_Wm1 // W1 branch diagnostics.
//#define BOOST_MATH_INSTRUMENT_LAMBERT_W_HALLEY // Halley refinement diagnostics.
//#define BOOST_MATH_INSTRUMENT_LAMBERT_W_SCHROEDER // Schroeder refinement diagnostics.
//#define BOOST_MATH_INSTRUMENT_LAMBERT_W_TERMS // Number of terms used for near-singularity series.
//#define BOOST_MATH_INSTRUMENT_LAMBERT_W0_NOT_BUILTIN // higher than built-in precision types approximation and refinement.
//#define BOOST_MATH_INSTRUMENT_LAMBERT_W_SINGULARITY_SERIES // Show evaluation of series near branch singularity.
//#define BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES_ITERATIONS // Show evaluation of series for small z.
//#define BOOST_MATH_INSTRUMENT_LAMBERT_W0_LOOKUP // Show results from lookup table.
#include <boost/config.hpp> // for BOOST_PLATFORM, BOOST_COMPILER, BOOST_STDLIB ...
#include <boost/version.hpp> // for BOOST_MSVC versions.
#include <boost/math/constants/constants.hpp> // For exp_minus_one == 3.67879441171442321595523770161460867e-01.
#include <boost/math/policies/policy.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp> // boost::multiprecision::cpp_dec_float_50
using boost::multiprecision::cpp_dec_float_50; // 50 decimal digits type.
using boost::multiprecision::cpp_dec_float_100; // 100 decimal digits type.
using boost::multiprecision::backends::cpp_dec_float;
using boost::multiprecision::number;
typedef number<cpp_dec_float<1000> > cpp_dec_float_1000; // 1000 decimal digit types
#include <boost/multiprecision/cpp_bin_float.hpp>
using boost::multiprecision::cpp_bin_float_double; // == double
using boost::multiprecision::cpp_bin_float_double_extended; // 80-bit long double emulation.
using boost::multiprecision::cpp_bin_float_quad; // 128-bit quad precision.
//[lambert_w_simple_examples_includes
#include <boost/math/special_functions/lambert_w.hpp> // For lambert_w function.
using boost::math::lambert_w0;
using boost::math::lambert_wm1;
//] //[/lambert_w_simple_examples_includes]
#include <iostream>
// using std::cout;
// using std::endl;
#include <exception>
#include <stdexcept>
#include <string>
#include <limits> // For std::numeric_limits.
//! Show value of z to the full possibly-significant max_digits10 precision of type T.
template<typename T>
void show_value(T z)
{
std::streamsize precision = std::cout.precision(std::numeric_limits<T>::max_digits10); // Save.
std::cout.precision(std::numeric_limits<T>::max_digits10); // Show all possibly significant digits.
std::ios::fmtflags flags(std::cout.flags());
std::cout.setf(std::ios_base::showpoint); // Include any trailing zeros.
std::cout << z;
// Restore:
std::cout.precision(precision);
std::cout.flags(flags);
} // template<typename T> void show_value(T z)
int main()
{
try
{
std::cout << "Lambert W simple examples." << std::endl;
using boost::math::constants::exp_minus_one; //-1/e, the branch point, a singularity ~= -0.367879.
// using statements needed for changing error handling policy.
using boost::math::policies::policy;
using boost::math::policies::make_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;
{
//[lambert_w_simple_examples_0
std::cout.precision(std::numeric_limits<double>::max_digits10);
// Show all potentially significant decimal digits,
std::cout << std::showpoint << std::endl;
// and show significant trailing zeros too.
double z = 10.;
double r = lambert_w0(z); // Default policy for double.
std::cout << "lambert_w0(z) = " << r << std::endl;
// lambert_w0(z) = 1.7455280027406994
//] [/lambert_w_simple_examples_0]
}
{
// Other floating-point types can be used too, here float.
// It is convenient to use a function like `show_value`
// to display all potentially significant decimal digits
// for the type, including any significant trailing zeros.
//[lambert_w_simple_examples_1
float z = 10.F;
float r;
r = lambert_w0(z); // Default policy digits10 = 7, digits2 = 24
std::cout << "lambert_w0(";
show_value(z);
std::cout << ") = ";
show_value(r);
std::cout << std::endl; // lambert_w0(10.0000000) = 1.74552798
//] //[/lambert_w_simple_examples_1]
}
{
// Example of an integer argument to lambert_w,
// showing that an integer is correctly promoted to a double.
//[lambert_w_simple_examples_2
std::cout.precision(std::numeric_limits<double>::max_digits10);
double r = lambert_w0(10); // Pass an int argument "10" that should be promoted to double argument.
std::cout << "lambert_w0(10) = " << r << std::endl; // lambert_w0(10) = 1.7455280027406994
double rp = lambert_w0(10);
std::cout << "lambert_w0(10) = " << rp << std::endl;
// lambert_w0(10) = 1.7455280027406994
auto rr = lambert_w0(10); // C++11 needed.
std::cout << "lambert_w0(10) = " << rr << std::endl;
// lambert_w0(10) = 1.7455280027406994 too, showing that rr has been promoted to double.
//] //[/lambert_w_simple_examples_2]
}
{
// Using multiprecision types to get much higher precision is painless.
//[lambert_w_simple_examples_3
cpp_dec_float_50 z("10");
// Note construction using a decimal digit string "10",
// NOT a floating-point double literal 10.
cpp_dec_float_50 r;
r = lambert_w0(z);
std::cout << "lambert_w0("; show_value(z); std::cout << ") = ";
show_value(r);
std::cout << std::endl;
// lambert_w0(10.000000000000000000000000000000000000000000000000000000000000000000000000000000) =
// 1.7455280027406993830743012648753899115352881290809413313533156980404446940000000
//] //[/lambert_w_simple_examples_3]
}
// Using multiprecision types to get multiprecision precision wrong!
{
//[lambert_w_simple_examples_4
cpp_dec_float_50 z(0.7777777777777777777777777777777777777777777777777777777777777777777777777);
// Compiler evaluates the nearest double-precision binary representation,
// from the max_digits10 of the floating_point literal double 0.7777777777777777777777777777...,
// so any extra digits in the multiprecision type
// beyond max_digits10 (usually 17) are random and meaningless.
cpp_dec_float_50 r;
r = lambert_w0(z);
std::cout << "lambert_w0(";
show_value(z);
std::cout << ") = "; show_value(r);
std::cout << std::endl;
// lambert_w0(0.77777777777777779011358916250173933804035186767578125000000000000000000000000000)
// = 0.48086152073210493501934682309060873341910109230469724725005039758139532631901386
//] //[/lambert_w_simple_examples_4]
}
{
//[lambert_w_simple_examples_4a
cpp_dec_float_50 z(0.9); // Construct from floating_point literal double 0.9.
cpp_dec_float_50 r;
r = lambert_w0(0.9);
std::cout << "lambert_w0(";
show_value(z);
std::cout << ") = "; show_value(r);
std::cout << std::endl;
// lambert_w0(0.90000000000000002220446049250313080847263336181640625000000000000000000000000000)
// = 0.52983296563343440510607251781038939952850341796875000000000000000000000000000000
std::cout << "lambert_w0(0.9) = " << lambert_w0(static_cast<double>(0.9))
// lambert_w0(0.9)
// = 0.52983296563343441
<< std::endl;
//] //[/lambert_w_simple_examples_4a]
}
{
// Using multiprecision types to get multiprecision precision right!
//[lambert_w_simple_examples_4b
cpp_dec_float_50 z("0.9"); // Construct from decimal digit string.
cpp_dec_float_50 r;
r = lambert_w0(z);
std::cout << "lambert_w0(";
show_value(z);
std::cout << ") = "; show_value(r);
std::cout << std::endl;
// 0.90000000000000000000000000000000000000000000000000000000000000000000000000000000)
// = 0.52983296563343441213336643954546304857788132269804249284012528304239956413801252
//] //[/lambert_w_simple_examples_4b]
}
// Getting extreme precision (1000 decimal digits) Lambert W values.
{
std::cout.precision(std::numeric_limits<cpp_dec_float_1000>::digits10);
cpp_dec_float_1000 z("2.0");
cpp_dec_float_1000 r;
r = lambert_w0(z);
std::cout << "lambert_w0(z) = " << r << std::endl;
// 0.8526055020137254913464724146953174668984533001514035087721073946525150656742630448965773783502494847334503972691804119834761668851953598826198984364998343940330324849743119327028383008883133161249045727544669202220292076639777316648311871183719040610274221013237163543451621208284315007250267190731048119566857455987975973474411544571619699938899354169616378479326962044241495398851839432070255805880208619490399218130868317114428351234208216131218024303904457925834743326836272959669122797896855064630871955955318383064292191644322931561534814178034773896739684452724587331245831001449498844495771266728242975586931792421997636537572767708722190588748148949667744956650966402600446780664924889043543203483210769017254907808218556111831854276511280553252641907484685164978750601216344998778097446525021666473925144772131644151718261199915247932015387685261438125313159125475113124470774926288823525823567568542843625471594347837868505309329628014463491611881381186810879712667681285740515197493390563
// Wolfram alpha command N[productlog[0, 2.0],1000] gives the identical result:
// 0.8526055020137254913464724146953174668984533001514035087721073946525150656742630448965773783502494847334503972691804119834761668851953598826198984364998343940330324849743119327028383008883133161249045727544669202220292076639777316648311871183719040610274221013237163543451621208284315007250267190731048119566857455987975973474411544571619699938899354169616378479326962044241495398851839432070255805880208619490399218130868317114428351234208216131218024303904457925834743326836272959669122797896855064630871955955318383064292191644322931561534814178034773896739684452724587331245831001449498844495771266728242975586931792421997636537572767708722190588748148949667744956650966402600446780664924889043543203483210769017254907808218556111831854276511280553252641907484685164978750601216344998778097446525021666473925144772131644151718261199915247932015387685261438125313159125475113124470774926288823525823567568542843625471594347837868505309329628014463491611881381186810879712667681285740515197493390563
}
{
//[lambert_w_simple_examples_error_policies
// Define an error handling policy:
typedef policy<
domain_error<throw_on_error>,
overflow_error<ignore_error> // possibly unwise?
> my_throw_policy;
std::cout.precision(std::numeric_limits<double>::max_digits10);
// Show all potentially significant decimal digits,
std::cout << std::showpoint << std::endl;
// and show significant trailing zeros too.
double z = +1;
std::cout << "Lambert W (" << z << ") = " << lambert_w0(z) << std::endl;
// Lambert W (1.0000000000000000) = 0.56714329040978384
std::cout << "\nLambert W (" << z << ", my_throw_policy()) = "
<< lambert_w0(z, my_throw_policy()) << std::endl;
// Lambert W (1.0000000000000000, my_throw_policy()) = 0.56714329040978384
//] //[/lambert_w_simple_example_error_policies]
}
{
// Show error reporting from passing a value to lambert_wm1 that is out of range,
// (and probably was meant to be passed to lambert_0 instead).
//[lambert_w_simple_examples_out_of_range
double z = +1.;
double r = lambert_wm1(z);
std::cout << "lambert_wm1(+1.) = " << r << std::endl;
//] [/lambert_w_simple_examples_out_of_range]
// Error in function boost::math::lambert_wm1<RealType>(<RealType>):
// Argument z = 1 is out of range (z <= 0) for Lambert W-1 branch! (Try Lambert W0 branch?)
}
}
catch (std::exception& ex)
{
std::cout << ex.what() << std::endl;
}
} // int main()
/*
Output:
//[lambert_w_simple_examples_error_message_1
Error in function boost::math::lambert_wm1<RealType>(<RealType>):
Argument z = 1 is out of range (z <= 0) for Lambert W-1 branch! (Try Lambert W0 branch?)
//] [/lambert_w_simple_examples_error_message_1]
*/
|