mirror of
https://github.com/boostorg/math.git
synced 2026-01-19 04:22:09 +00:00
Precision updated, quadrature notes added, need prime notes
This commit is contained in:
@@ -120,7 +120,7 @@ This manual is also available in <a href="http://sourceforge.net/projects/boost/
|
||||
</div>
|
||||
</div>
|
||||
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
|
||||
<td align="left"><p><small>Last revised: July 17, 2018 at 16:28:57 GMT</small></p></td>
|
||||
<td align="left"><p><small>Last revised: July 19, 2018 at 15:38:32 GMT</small></p></td>
|
||||
<td align="right"><div class="copyright-footer"></div></td>
|
||||
</tr></table>
|
||||
<hr>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
|
||||
<a name="id1865620"></a>Function Index</h2></div></div></div>
|
||||
<a name="id1854868"></a>Function Index</h2></div></div></div>
|
||||
<p><a class="link" href="s01.html#idx_id_0">2</a> <a class="link" href="s01.html#idx_id_1">4</a> <a class="link" href="s01.html#idx_id_2">A</a> <a class="link" href="s01.html#idx_id_3">B</a> <a class="link" href="s01.html#idx_id_4">C</a> <a class="link" href="s01.html#idx_id_5">D</a> <a class="link" href="s01.html#idx_id_6">E</a> <a class="link" href="s01.html#idx_id_7">F</a> <a class="link" href="s01.html#idx_id_8">G</a> <a class="link" href="s01.html#idx_id_9">H</a> <a class="link" href="s01.html#idx_id_10">I</a> <a class="link" href="s01.html#idx_id_11">J</a> <a class="link" href="s01.html#idx_id_12">K</a> <a class="link" href="s01.html#idx_id_13">L</a> <a class="link" href="s01.html#idx_id_14">M</a> <a class="link" href="s01.html#idx_id_15">N</a> <a class="link" href="s01.html#idx_id_16">O</a> <a class="link" href="s01.html#idx_id_17">P</a> <a class="link" href="s01.html#idx_id_18">Q</a> <a class="link" href="s01.html#idx_id_19">R</a> <a class="link" href="s01.html#idx_id_20">S</a> <a class="link" href="s01.html#idx_id_21">T</a> <a class="link" href="s01.html#idx_id_22">U</a> <a class="link" href="s01.html#idx_id_23">V</a> <a class="link" href="s01.html#idx_id_24">W</a> <a class="link" href="s01.html#idx_id_25">X</a> <a class="link" href="s01.html#idx_id_26">Y</a> <a class="link" href="s01.html#idx_id_27">Z</a></p>
|
||||
<div class="variablelist"><dl class="variablelist">
|
||||
<dt>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
|
||||
<a name="id1893898"></a>Class Index</h2></div></div></div>
|
||||
<a name="id1880806"></a>Class Index</h2></div></div></div>
|
||||
<p><a class="link" href="s02.html#idx_id_30">A</a> <a class="link" href="s02.html#idx_id_31">B</a> <a class="link" href="s02.html#idx_id_32">C</a> <a class="link" href="s02.html#idx_id_33">D</a> <a class="link" href="s02.html#idx_id_34">E</a> <a class="link" href="s02.html#idx_id_35">F</a> <a class="link" href="s02.html#idx_id_36">G</a> <a class="link" href="s02.html#idx_id_37">H</a> <a class="link" href="s02.html#idx_id_38">I</a> <a class="link" href="s02.html#idx_id_41">L</a> <a class="link" href="s02.html#idx_id_42">M</a> <a class="link" href="s02.html#idx_id_43">N</a> <a class="link" href="s02.html#idx_id_44">O</a> <a class="link" href="s02.html#idx_id_45">P</a> <a class="link" href="s02.html#idx_id_46">Q</a> <a class="link" href="s02.html#idx_id_47">R</a> <a class="link" href="s02.html#idx_id_48">S</a> <a class="link" href="s02.html#idx_id_49">T</a> <a class="link" href="s02.html#idx_id_50">U</a> <a class="link" href="s02.html#idx_id_52">W</a></p>
|
||||
<div class="variablelist"><dl class="variablelist">
|
||||
<dt>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
|
||||
<a name="id1892844"></a>Typedef Index</h2></div></div></div>
|
||||
<a name="id1881997"></a>Typedef Index</h2></div></div></div>
|
||||
<p><a class="link" href="s03.html#idx_id_58">A</a> <a class="link" href="s03.html#idx_id_59">B</a> <a class="link" href="s03.html#idx_id_60">C</a> <a class="link" href="s03.html#idx_id_61">D</a> <a class="link" href="s03.html#idx_id_62">E</a> <a class="link" href="s03.html#idx_id_63">F</a> <a class="link" href="s03.html#idx_id_64">G</a> <a class="link" href="s03.html#idx_id_65">H</a> <a class="link" href="s03.html#idx_id_66">I</a> <a class="link" href="s03.html#idx_id_69">L</a> <a class="link" href="s03.html#idx_id_71">N</a> <a class="link" href="s03.html#idx_id_72">O</a> <a class="link" href="s03.html#idx_id_73">P</a> <a class="link" href="s03.html#idx_id_75">R</a> <a class="link" href="s03.html#idx_id_76">S</a> <a class="link" href="s03.html#idx_id_77">T</a> <a class="link" href="s03.html#idx_id_78">U</a> <a class="link" href="s03.html#idx_id_79">V</a> <a class="link" href="s03.html#idx_id_80">W</a></p>
|
||||
<div class="variablelist"><dl class="variablelist">
|
||||
<dt>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
|
||||
<a name="id1897864"></a>Macro Index</h2></div></div></div>
|
||||
<a name="id1884456"></a>Macro Index</h2></div></div></div>
|
||||
<p><a class="link" href="s04.html#idx_id_87">B</a> <a class="link" href="s04.html#idx_id_91">F</a></p>
|
||||
<div class="variablelist"><dl class="variablelist">
|
||||
<dt>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
|
||||
<a name="id1900030"></a>Index</h2></div></div></div>
|
||||
<a name="id1889054"></a>Index</h2></div></div></div>
|
||||
<p><a class="link" href="s05.html#idx_id_112">2</a> <a class="link" href="s05.html#idx_id_113">4</a> <a class="link" href="s05.html#idx_id_114">A</a> <a class="link" href="s05.html#idx_id_115">B</a> <a class="link" href="s05.html#idx_id_116">C</a> <a class="link" href="s05.html#idx_id_117">D</a> <a class="link" href="s05.html#idx_id_118">E</a> <a class="link" href="s05.html#idx_id_119">F</a> <a class="link" href="s05.html#idx_id_120">G</a> <a class="link" href="s05.html#idx_id_121">H</a> <a class="link" href="s05.html#idx_id_122">I</a> <a class="link" href="s05.html#idx_id_123">J</a> <a class="link" href="s05.html#idx_id_124">K</a> <a class="link" href="s05.html#idx_id_125">L</a> <a class="link" href="s05.html#idx_id_126">M</a> <a class="link" href="s05.html#idx_id_127">N</a> <a class="link" href="s05.html#idx_id_128">O</a> <a class="link" href="s05.html#idx_id_129">P</a> <a class="link" href="s05.html#idx_id_130">Q</a> <a class="link" href="s05.html#idx_id_131">R</a> <a class="link" href="s05.html#idx_id_132">S</a> <a class="link" href="s05.html#idx_id_133">T</a> <a class="link" href="s05.html#idx_id_134">U</a> <a class="link" href="s05.html#idx_id_135">V</a> <a class="link" href="s05.html#idx_id_136">W</a> <a class="link" href="s05.html#idx_id_137">X</a> <a class="link" href="s05.html#idx_id_138">Y</a> <a class="link" href="s05.html#idx_id_139">Z</a></p>
|
||||
<div class="variablelist"><dl class="variablelist">
|
||||
<dt>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<a name="math_toolkit.conventions"></a><a class="link" href="conventions.html" title="Document Conventions">Document Conventions</a>
|
||||
</h2></div></div></div>
|
||||
<p>
|
||||
<a class="indexterm" name="id1001609"></a>
|
||||
<a class="indexterm" name="id985976"></a>
|
||||
</p>
|
||||
<p>
|
||||
This documentation aims to use of the following naming and formatting conventions.
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<a name="math_toolkit.navigation"></a><a class="link" href="navigation.html" title="Navigation">Navigation</a>
|
||||
</h2></div></div></div>
|
||||
<p>
|
||||
<a class="indexterm" name="id1001465"></a>
|
||||
<a class="indexterm" name="id985810"></a>
|
||||
</p>
|
||||
<p>
|
||||
Boost.Math documentation is provided in both HTML and PDF formats.
|
||||
|
||||
@@ -37,7 +37,7 @@ It is also called the Omega function, the inverse function of ['f(W) = W e[super
|
||||
|
||||
On the z-interval \[0, [infin]\] there is just one real solution.
|
||||
On the interval (-1/e, 0) there are two real solutions on two branches called variously W0, W+, W-1, Wp, Wm, W-.
|
||||
Two principal branches functions called `lambert_w0` and `lambert_wm1`
|
||||
Two principal branches functions called `lambert_w0` and `lambert_wm1`, and their 1st derivative,
|
||||
are provided by Boost's real-only implementation.
|
||||
|
||||
In the graphs below, the red line is the W0 branch, and the blue line the W-1 branch.
|
||||
@@ -126,7 +126,7 @@ Note the expected zeros for all places up to 50 - and the correct Lambert W resu
|
||||
(It is just as easy to compute even higher precisions,
|
||||
at least to thousands of decimal digits, but not shown here for brevity.
|
||||
See [@../../example/lambert_w_simple_examples.cpp lambert_w_simple_examples.cpp]
|
||||
).
|
||||
for comparison of an evaluation at 1000 decimal digit precision with __WolframAlpha).
|
||||
|
||||
Policies can be used to control what action to take on errors:
|
||||
|
||||
@@ -205,42 +205,82 @@ The symbolic algebra program __Maple also computes Lambert W to an arbitrary pre
|
||||
|
||||
[h4:precision Controlling the compromise between Precision and Speed]
|
||||
|
||||
This implementation provides good precision and excellent speed.
|
||||
[h5:small_floats Floating-point types `double` and `float`]
|
||||
This implementation provides good precision and excellent speed for __fundamental types `float` and `double`.
|
||||
|
||||
All the functions usually return values within a few __ulp
|
||||
for the floating-point type, except for very small arguments very near zero,
|
||||
and for arguments very close to the singularity at the branch point.
|
||||
|
||||
By default, this implementation provides the best possible speed.
|
||||
Very slightly higher precision and less bias can be obtained by adding a __halley step refinement,
|
||||
Very slightly average higher precision and less bias might be obtained
|
||||
by adding a __halley step refinement,
|
||||
but at the cost of more than doubling the run time.
|
||||
|
||||
The 'best' evaluation (the nearest __representable) can be achieved by `static_cast`ing from a
|
||||
higher precision type, typically a __multiprecision type like `cpp_bin_float_50`,
|
||||
at the cost of increasing run-time >100-fold;
|
||||
this has been used here to provide reference values for testing.
|
||||
|
||||
[import ../../example/lambert_w_precision_example.cpp]
|
||||
|
||||
[lambert_w_precision_1]
|
||||
|
||||
The output for ['z = 1.F] is:
|
||||
|
||||
[lambert_w_precision_output_1]
|
||||
|
||||
showing no improvement from the Halley refinement, but for ['z = 10.F]
|
||||
we need a Halley refinement (or few) to get the last bit or two correct.
|
||||
|
||||
[lambert_w_precision_output_1a]
|
||||
|
||||
[h5:big_floats Floating-point types larger than double]
|
||||
|
||||
For floating-point types with precision greater than `double` and `float` __fundamental_types,
|
||||
a `double` evaluation is used as a first approximation followed by Halley refinement,
|
||||
using a single step where it can be predicted that this will be sufficient,
|
||||
only using __Halley iteration when necessary.
|
||||
and only using __halley iteration when necessary.
|
||||
Higher precision types are always going to be [*very, very much slower].
|
||||
|
||||
The 'best' evaluation (the nearest __representable) can be achieved by `static_cast`ing from a
|
||||
higher precision type, typically a __multiprecision type like `cpp_bin_float_50`,
|
||||
but at the cost of increasing run-time >100-fold;
|
||||
this has been used here to provide our reference values for testing.
|
||||
|
||||
[import ../../example/lambert_w_precision_example.cpp]
|
||||
|
||||
For example, we get a reference value using a high precision type, for example;
|
||||
|
||||
`using boost::multiprecision::cpp_bin_float_50;`
|
||||
|
||||
that uses Halley iteration to refine until it is as precise as possible for this `cpp_bin_float_50` type.
|
||||
|
||||
As a further check we can compare this with a __WolframAlpha computation
|
||||
using command [^N\[ProductLog\[10.\], 50\]] to get 50 decimal digits
|
||||
and similarly [^N\[ProductLog\[10.\], 17\]] to get the nearest representable for 64-bit `double` precision.
|
||||
|
||||
[lambert_w_precision_reference_w]
|
||||
|
||||
giving us the same nearest representable using 64-bit `double` as `1.7455280027406994`.
|
||||
|
||||
However, the rational polynomial and Fukushima Schroder approximations are so good for type `float` and `double`
|
||||
that negligible improvement is gained from a `double` Halley step.
|
||||
|
||||
This is shown with [@../../example/lambert_w_precision_example.cpp lambert_w_precision_example.cpp]
|
||||
for Lambert W0:
|
||||
|
||||
[lambert_w_precision_1]
|
||||
|
||||
with this output:
|
||||
|
||||
[lambert_w_precision_output_1]
|
||||
|
||||
and then for W-1:
|
||||
|
||||
[lambert_w_precision_2]
|
||||
|
||||
with this output:
|
||||
|
||||
[lambert_w_precision_output_2]
|
||||
|
||||
[h5:differences_distribution Distribution of differences from 'best' `double` evaluations]
|
||||
|
||||
The distribution of differences from 'best' are shown in these graphs comparing `double` precision evaluations
|
||||
with reference 'best' z50 evaluations using `cpp_bin_float_50` type reduced to `double` with `static_cast<double(z50)` :
|
||||
|
||||
[graph lambert_w_errors_graph]
|
||||
|
||||
[graph lambert_wm1_errors_graph]
|
||||
|
||||
As noted in the implementation section, the distribution of these differences is somewhat biased
|
||||
for Lambert W-1 and this might be reduced using a `double` Halley step at small runtime cost.
|
||||
But if you are serisouly concerned to get really precise computations,
|
||||
the only way is using a higher precision type and then reduce to the desired type.
|
||||
Fortunately, __multiprecision makes this very easy to program, if much slower.
|
||||
|
||||
[h4:edge_cases Edge and Corner cases]
|
||||
|
||||
[h5:w0_edges w0 Branch]
|
||||
@@ -430,19 +470,16 @@ For example, table below a test of Lambert W0 10000 values of argument z coverin
|
||||
[[after Halley step] [ 9710 ] [ 288 ] [ 2 ] [0] [ 292 ] [22]]
|
||||
] [/table:lambert_w0_Fukushima W0]
|
||||
|
||||
|
||||
Lambert W0 values computed using the Fukushima method with Schroeder refinement gave about 1/6 lambert_w0 values that are
|
||||
one bit different from the 'best', and < 1% that are a few bits 'wrong'.
|
||||
If a Halley refinement step is added, only 1 in 30 are even one bit different, and only 2 two bits 'wrong'.
|
||||
|
||||
|
||||
[table:lambert_w0_plus_halley Rational polynomial Lambert W0 and typical improvement from a single Halley step.
|
||||
[[Method] [Exact] [One_bit] [Two_bits] [Few_bits] [inexact] [bias]]
|
||||
[[rational/polynomial] [7135] [ 2863 ] [ 2 ] [0] [ 2867 ] [ -59] ]
|
||||
[[after Halley step ] [ 9724 ] [273] [ 3 ] [0] [ 279 ] [5] ]
|
||||
] [/table:lambert_w0_plus_halley]
|
||||
|
||||
|
||||
With the rational polynomial approximation method, there are a third one bit from the best and none more than two bits.
|
||||
Adding a Halley step (or iteration) reduces the number that are one bit different from about a third down to one in 30;
|
||||
this is unavoidable 'computational noise'.
|
||||
@@ -696,7 +733,22 @@ precision can be much lower, as might be expected.
|
||||
[@../../example/lambert_w_simple_examples.cpp lambert_w_simple_examples.cpp]
|
||||
[@../../test/test_lambert_w.cpp test_lambert_w.cpp] contains routine tests using __boost_test.
|
||||
|
||||
Two macros provide optional tests if #defined before BOOST_TEST_MAIN.
|
||||
[h5:quadrature_testing Testing with quadrature]
|
||||
|
||||
A further method of testing over a wide range of argument z values was devised by Nick Thompson
|
||||
(partly to test the recently added quadrature routines).
|
||||
These are definite integral formulas involving the W function that are exactly known constants,
|
||||
for example, LambertW0(1/(z[sup2]) == [sqrt](2[pi]),
|
||||
see [@https://en.wikipedia.org/wiki/Lambert_W_function#Definite_integrals Definite Integrals].
|
||||
Some care was needed to avoid overflow and underflow as the function must evaluate to a finite result over the entire range.
|
||||
|
||||
|
||||
These are not routinely evaluated by the Boost testers,
|
||||
but can be run by defining a macro BOOST_MATH_LAMBERT_W_INTEGRALS.
|
||||
|
||||
|
||||
|
||||
Three macros provide optional tests if #defined before BOOST_TEST_MAIN.
|
||||
|
||||
* BOOST_MATH_TEST_MULTIPRECISION Adds test for __multiprecision types.
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <boost/exception/exception.hpp> // boost::exception
|
||||
#include <boost/math/constants/constants.hpp> // For exp_minus_one == 3.67879441171442321595523770161460867e-01.
|
||||
#include <boost/math/policies/policy.hpp>
|
||||
#include <boost/math/special_functions/next.hpp> // for float_distance.
|
||||
#include <boost/math/special_functions/relative_difference.hpp> // for relative and epsilon difference.
|
||||
|
||||
// Built-in/fundamental GCC float128 or Intel Quad 128-bit type, if available.
|
||||
#ifdef __GNUC__
|
||||
@@ -64,47 +66,144 @@ int main()
|
||||
using boost::math::policies::domain_error;
|
||||
using boost::math::policies::throw_on_error;
|
||||
|
||||
//[lambert_w_precision_reference_w
|
||||
|
||||
using boost::multiprecision::cpp_bin_float_50;
|
||||
using boost::math::float_distance;
|
||||
|
||||
cpp_bin_float_50 z("10."); // Note use a decimal digit string, not a double 10.
|
||||
cpp_bin_float_50 r;
|
||||
std::cout.precision(std::numeric_limits<cpp_bin_float_50>::digits10);
|
||||
|
||||
r = lambert_w0(z); // Default policy.
|
||||
std::cout << "lambert_w0(z) cpp_bin_float_50 = " << r << std::endl;
|
||||
//lambert_w0(z) cpp_bin_float_50 = 1.7455280027406993830743012648753899115352881290809
|
||||
// [N[productlog[10], 50]] == 1.7455280027406993830743012648753899115352881290809
|
||||
std::cout.precision(std::numeric_limits<double>::max_digits10);
|
||||
std::cout << "lambert_w0(z) static_cast from cpp_bin_float_50 = "
|
||||
<< static_cast<double>(r) << std::endl;
|
||||
// double lambert_w0(z) static_cast from cpp_bin_float_50 = 1.7455280027406994
|
||||
// [N[productlog[10], 17]] == 1.7455280027406994
|
||||
std::cout << "bits different from Wolfram = "
|
||||
<< static_cast<int>(float_distance(static_cast<double>(r), 1.7455280027406994))
|
||||
<< std::endl; // 0
|
||||
|
||||
|
||||
//] [/lambert_w_precision_reference_w]
|
||||
|
||||
//[lambert_w_precision_0
|
||||
std::cout.precision(std::numeric_limits<float>::max_digits10); // Show all potentially significant decimal digits,
|
||||
std::cout << std::showpoint << std::endl; // and show any significant trailing zeros too.
|
||||
|
||||
double x = 10.;
|
||||
float x = 10.;
|
||||
std::cout << "Lambert W (" << x << ") = " << lambert_w0(x) << std::endl;
|
||||
//
|
||||
|
||||
|
||||
|
||||
//] [/lambert_w_precision_0]
|
||||
|
||||
/*
|
||||
//[lambert_w_precision_output_0
|
||||
|
||||
Lambert W (10.0000000) = 1.74552800
|
||||
//] [/lambert_w_precision_output_0]
|
||||
*/
|
||||
|
||||
{ // Lambert W0 Halley step example
|
||||
//[lambert_w_precision_1
|
||||
|
||||
using boost::math::lambert_w_detail::lambert_w_halley_step;
|
||||
using boost::math::epsilon_difference;
|
||||
using boost::math::relative_difference;
|
||||
|
||||
std::cout << std::showpoint << std::endl; // and show any significant trailing zeros too.
|
||||
std::cout.precision(std::numeric_limits<double>::max_digits10); // 17 decimal digits for double.
|
||||
|
||||
cpp_bin_float_50 z50("1.23"); // Note: use a decimal digit string, not a double 1.23!
|
||||
double z = static_cast<double>(z50);
|
||||
cpp_bin_float_50 w50;
|
||||
w50 = lambert_w0(z50);
|
||||
std::cout.precision(std::numeric_limits<cpp_bin_float_50>::max_digits10); // 50 decimal digits.
|
||||
std::cout << "Reference Lambert W (" << z << ") =\n "
|
||||
<< w50 << std::endl;
|
||||
std::cout.precision(std::numeric_limits<double>::max_digits10); // 17 decimal digits for double.
|
||||
double wr = static_cast<double>(w50);
|
||||
std::cout << "Reference Lambert W (" << z << ") = " << wr << std::endl;
|
||||
|
||||
double z = 10.;
|
||||
double w = lambert_w0(z);
|
||||
std::cout << "Lambert W (" << x << ") = " << lambert_w0(z) << std::endl;
|
||||
std::cout << "Rat/poly Lambert W (" << z << ") = " << lambert_w0(z) << std::endl;
|
||||
// Add a Halley step to the value obtained from rational polynomial approximation.
|
||||
double ww = lambert_w_halley_step(lambert_w0(z), z);
|
||||
std::cout << "Lambert W (" << x << ") = " << lambert_w_halley_step(lambert_w0(z), z) << std::endl;
|
||||
std::cout << "Halley Step Lambert W (" << z << ") = " << lambert_w_halley_step(lambert_w0(z), z) << std::endl;
|
||||
|
||||
std::cout << "difference from Halley step " << w - ww << std::endl;
|
||||
std::cout << "absolute difference from Halley step = " << w - ww << std::endl;
|
||||
std::cout << "relative difference from Halley step = " << relative_difference(w, ww) << std::endl;
|
||||
std::cout << "epsilon difference from Halley step = " << epsilon_difference(w, ww) << std::endl;
|
||||
std::cout << "epsilon for float = " << std::numeric_limits<double>::epsilon() << std::endl;
|
||||
std::cout << "bits different from Halley step = " << static_cast<int>(float_distance(w, ww)) << std::endl;
|
||||
//] [/lambert_w_precision_1]
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
//[lambert_w_precision_output_1
|
||||
|
||||
Reference Lambert W (1.2299999999999999822364316059974953532218933105468750) =
|
||||
0.64520356959320237759035605255334853830173300262666480
|
||||
Reference Lambert W (1.2300000000000000) = 0.64520356959320235
|
||||
Rat/poly Lambert W (1.2300000000000000) = 0.64520356959320224
|
||||
Halley Step Lambert W (1.2300000000000000) = 0.64520356959320235
|
||||
absolute difference from Halley step = -1.1102230246251565e-16
|
||||
relative difference from Halley step = 1.7207329236029286e-16
|
||||
epsilon difference from Halley step = 0.77494921535422934
|
||||
epsilon for float = 2.2204460492503131e-16
|
||||
bits different from Halley step = 1
|
||||
//] [/lambert_w_precision_output_1]
|
||||
*/
|
||||
|
||||
} // Lambert W0 Halley step example
|
||||
|
||||
{ // Lambert W-1 Halley step example
|
||||
//[lambert_w_precision_2
|
||||
using boost::math::lambert_w_detail::lambert_w_halley_step;
|
||||
using boost::math::epsilon_difference;
|
||||
using boost::math::relative_difference;
|
||||
|
||||
std::cout << std::showpoint << std::endl; // and show any significant trailing zeros too.
|
||||
std::cout.precision(std::numeric_limits<double>::max_digits10); // 17 decimal digits for double.
|
||||
|
||||
cpp_bin_float_50 z50("-0.123"); // Note: use a decimal digit string, not a double -1.234!
|
||||
double z = static_cast<double>(z50);
|
||||
cpp_bin_float_50 wm1_50;
|
||||
wm1_50 = lambert_wm1(z50);
|
||||
std::cout.precision(std::numeric_limits<cpp_bin_float_50>::max_digits10); // 50 decimal digits.
|
||||
std::cout << "Reference Lambert W-1 (" << z << ") =\n "
|
||||
<< wm1_50 << std::endl;
|
||||
std::cout.precision(std::numeric_limits<double>::max_digits10); // 17 decimal digits for double.
|
||||
double wr = static_cast<double>(wm1_50);
|
||||
std::cout << "Reference Lambert W-1 (" << z << ") = " << wr << std::endl;
|
||||
|
||||
double w = lambert_wm1(z);
|
||||
std::cout << "Rat/poly Lambert W-1 (" << z << ") = " << lambert_wm1(z) << std::endl;
|
||||
// Add a Halley step to the value obtained from rational polynomial approximation.
|
||||
double ww = lambert_w_halley_step(lambert_wm1(z), z);
|
||||
std::cout << "Halley Step Lambert W (" << z << ") = " << lambert_w_halley_step(lambert_wm1(z), z) << std::endl;
|
||||
|
||||
std::cout << "absolute difference from Halley step = " << w - ww << std::endl;
|
||||
std::cout << "relative difference from Halley step = " << relative_difference(w, ww) << std::endl;
|
||||
std::cout << "epsilon difference from Halley step = " << epsilon_difference(w, ww) << std::endl;
|
||||
std::cout << "epsilon for float = " << std::numeric_limits<double>::epsilon() << std::endl;
|
||||
std::cout << "bits different from Halley step = " << static_cast<int>(float_distance(w, ww)) << std::endl;
|
||||
//] [/lambert_w_precision_2]
|
||||
}
|
||||
/*
|
||||
//[lambert_w_precision_output_2
|
||||
Reference Lambert W-1 (-0.12299999999999999822364316059974953532218933105468750) =
|
||||
-3.2849102557740360179084675531714935199110302996513384
|
||||
Reference Lambert W-1 (-0.12300000000000000) = -3.2849102557740362
|
||||
Rat/poly Lambert W-1 (-0.12300000000000000) = -3.2849102557740357
|
||||
Halley Step Lambert W (-0.12300000000000000) = -3.2849102557740362
|
||||
absolute difference from Halley step = 4.4408920985006262e-16
|
||||
relative difference from Halley step = 1.3519066740696092e-16
|
||||
epsilon difference from Halley step = 0.60884463935795785
|
||||
epsilon for float = 2.2204460492503131e-16
|
||||
bits different from Halley step = -1
|
||||
//] [/lambert_w_precision_output_2]
|
||||
*/
|
||||
|
||||
// z = 10.F needs Halley to get the last bit or two correct.
|
||||
//[lambert_w_precision_output_1a
|
||||
|
||||
//] [/lambert_w_precision_output_1a]
|
||||
*/
|
||||
|
||||
// Similar example using cpp_bin_float_quad (128-bit floating-point types).
|
||||
|
||||
@@ -126,6 +225,7 @@ int main()
|
||||
cpp_dec_float_50 z("10");
|
||||
cpp_dec_float_50 r;
|
||||
std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10);
|
||||
|
||||
r = lambert_w0(z); // Default policy.
|
||||
std::cout << "lambert_w0(z) cpp_dec_float_50 = " << r << std::endl; // 0.56714329040978387299996866221035554975381578718651
|
||||
std::cout.precision(std::numeric_limits<cpp_bin_float_quad>::max_digits10);
|
||||
@@ -152,8 +252,6 @@ int main()
|
||||
// lambert_w0(z) cpp_dec_float_50 cast to quad = 1.745528002740699383074301264875389837
|
||||
// lambert_w0(z) cpp_dec_float_50 cast to quad = 1.74552800274069938307430126487539
|
||||
}
|
||||
|
||||
// std::cout << "Lambert W (" << xd << ") = " << lambert_w0(xd) << std::endl; //
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user