]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | // Copyright Paul A. Bristow 2016, 2017, 2018. |
2 | // Copyright John Maddock 2016. | |
3 | ||
4 | // Use, modification and distribution are subject to the | |
5 | // Boost Software License, Version 1.0. | |
6 | // (See accompanying file LICENSE_1_0.txt | |
7 | // or copy at http://www.boost.org/LICENSE_1_0.txt) | |
8 | ||
9 | // test_lambert_w.cpp | |
10 | //! \brief Basic sanity tests for Lambert W function using algorithms | |
11 | // informed by Thomas Luu, Darko Veberic and Tosio Fukushima for W0 | |
12 | // and rational polynomials by John Maddock. | |
13 | ||
14 | // #define BOOST_MATH_TEST_MULTIPRECISION // Add tests for several multiprecision types (not just built-in). | |
15 | // #define BOOST_MATH_TEST_FLOAT128 // Add test using float128 type (GCC only, needing gnu++17 and quadmath library). | |
16 | ||
1e59de90 TL |
17 | #include <climits> |
18 | #include <cfloat> | |
19 | #if defined(BOOST_MATH_TEST_FLOAT128) && (LDBL_MANT_DIG > 100) | |
20 | // | |
21 | // Mixing __float128 and long double results in: | |
22 | // error: __float128 and long double cannot be used in the same expression | |
23 | // whenever long double is a [possibly quasi-] quad precision type. | |
24 | // | |
25 | #undef BOOST_MATH_TEST_FLOAT128 | |
26 | #endif | |
27 | ||
92f5a8d4 TL |
28 | #ifdef BOOST_MATH_TEST_FLOAT128 |
29 | #include <boost/cstdfloat.hpp> // For float_64_t, float128_t. Must be first include! | |
30 | #endif // #ifdef #ifdef BOOST_MATH_TEST_FLOAT128 | |
31 | // Needs gnu++17 for BOOST_HAS_FLOAT128 | |
32 | #include <boost/config.hpp> // for BOOST_MSVC definition etc. | |
33 | #include <boost/version.hpp> // for BOOST_MSVC versions. | |
34 | ||
35 | // Boost macros | |
36 | #define BOOST_TEST_MAIN | |
37 | #define BOOST_LIB_DIAGNOSTIC "on" // Report library file details. | |
f67539c2 TL |
38 | //#define BOOST_TEST_LOG_LEVEL all // Appears not to work??? |
39 | // run with --log_level="message" | |
40 | ||
92f5a8d4 TL |
41 | #include <boost/test/included/unit_test.hpp> // Boost.Test |
42 | // #include <boost/test/unit_test.hpp> // Boost.Test | |
43 | #include <boost/test/tools/floating_point_comparison.hpp> | |
44 | ||
45 | #include <boost/array.hpp> | |
46 | #include <boost/lexical_cast.hpp> | |
47 | #include <boost/type_traits/is_constructible.hpp> | |
48 | ||
49 | #ifdef BOOST_MATH_TEST_MULTIPRECISION | |
50 | #include <boost/multiprecision/cpp_dec_float.hpp> // boost::multiprecision::cpp_dec_float_50 | |
51 | using boost::multiprecision::cpp_dec_float_50; | |
52 | ||
53 | #include <boost/multiprecision/cpp_bin_float.hpp> | |
54 | using boost::multiprecision::cpp_bin_float_quad; | |
55 | ||
56 | #include <boost/math/concepts/real_concept.hpp> | |
57 | ||
58 | #ifdef BOOST_MATH_TEST_FLOAT128 | |
59 | ||
60 | #ifdef BOOST_HAS_FLOAT128 | |
61 | // Including this header below without float128 triggers: | |
62 | // fatal error C1189: #error: "Sorry compiler is neither GCC, not Intel, don't know how to configure this header." | |
63 | #include <boost/multiprecision/float128.hpp> | |
64 | using boost::multiprecision::float128; | |
65 | #endif // ifdef BOOST_HAS_FLOAT128 | |
66 | #endif // #ifdef #ifdef BOOST_MATH_TEST_FLOAT128 | |
67 | ||
68 | #endif // #ifdef BOOST_MATH_TEST_MULTIPRECISION | |
69 | ||
70 | //#include <boost/fixed_point/fixed_point.hpp> // If available. | |
71 | ||
72 | #include <boost/math/concepts/real_concept.hpp> // for real_concept tests. | |
f67539c2 | 73 | #include <boost/math/special_functions/fpclassify.hpp> // isnan, isfinite. |
92f5a8d4 TL |
74 | #include <boost/math/special_functions/next.hpp> // float_next, float_prior |
75 | using boost::math::float_next; | |
76 | using boost::math::float_prior; | |
77 | #include <boost/math/special_functions/ulp.hpp> // ulp | |
78 | ||
79 | #include <boost/math/tools/test_value.hpp> // for create_test_value and macro BOOST_MATH_TEST_VALUE. | |
80 | #include <boost/math/policies/policy.hpp> | |
81 | using boost::math::policies::digits2; | |
82 | using boost::math::policies::digits10; | |
83 | #include <boost/math/special_functions/lambert_w.hpp> // For Lambert W lambert_w function. | |
84 | using boost::math::lambert_wm1; | |
85 | using boost::math::lambert_w0; | |
86 | ||
87 | #include "table_type.hpp" | |
88 | ||
89 | #ifndef SC_ | |
1e59de90 | 90 | # define SC_(x) BOOST_MATH_HUGE_TEST_VALUE(typename table_type<T>::type, x) |
92f5a8d4 TL |
91 | #endif |
92 | ||
93 | ||
94 | #include <limits> | |
95 | #include <cmath> | |
96 | #include <typeinfo> | |
97 | #include <iostream> | |
98 | #include <exception> | |
99 | ||
100 | std::string show_versions(void); | |
101 | ||
102 | //! Build a message of information about build, architecture, address model, platform, ... | |
103 | std::string show_versions(void) | |
104 | { | |
105 | // Some of this information can also be obtained from running with a Custom Post-build step | |
106 | // adding the option --build_info=yes | |
107 | // "$(TargetDir)$(TargetName).exe" --build_info=yes | |
108 | ||
109 | std::ostringstream message; | |
110 | ||
111 | message << "Program: " << __FILE__ << "\n"; | |
112 | #ifdef __TIMESTAMP__ | |
113 | message << __TIMESTAMP__; | |
114 | #endif | |
115 | message << "\nBuildInfo:\n" " Platform " << BOOST_PLATFORM; | |
116 | // http://stackoverflow.com/questions/1505582/determining-32-vs-64-bit-in-c | |
117 | #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) | |
118 | message << ", 64-bit."; | |
119 | #else | |
120 | message << ", 32-bit."; | |
121 | #endif | |
122 | ||
123 | message << "\n Compiler " BOOST_COMPILER; | |
124 | #ifdef BOOST_MSC_VER | |
125 | #ifdef _MSC_FULL_VER | |
126 | message << "\n MSVC version " << BOOST_STRINGIZE(_MSC_FULL_VER) << "."; | |
127 | #endif | |
128 | #ifdef __WIN64 | |
129 | mess age << "\n WIN64" << std::endl; | |
130 | #endif // __WIN64 | |
131 | #ifdef _WIN32 | |
132 | message << "\n WIN32" << std::endl; | |
133 | #endif // __WIN32 | |
134 | #endif | |
135 | #ifdef __GNUC__ | |
136 | //PRINT_MACRO(__GNUC__); | |
137 | //PRINT_MACRO(__GNUC_MINOR__); | |
138 | //PRINT_MACRO(__GNUC_PATCH__); | |
139 | std::cout << "GCC " << __VERSION__ << std::endl; | |
140 | //PRINT_MACRO(LONG_MAX); | |
141 | #endif // __GNUC__ | |
142 | ||
143 | #ifdef __MINGW64__ | |
144 | std::cout << "MINGW64 " << __MINGW32_MAJOR_VERSION << __MINGW32_MINOR_VERSION << std::endl; | |
145 | // | |
146 | // << __MINGW64_MAJOR_VERSION << __MINGW64_MINOR_VERSION << std::endl; not declared in this scope??? | |
147 | #endif // __MINGW64__ | |
148 | ||
149 | #ifdef __MINGW32__ | |
150 | std::cout << "MINGW64 " << __MINGW32_MAJOR_VERSION << __MINGW32_MINOR_VERSION << std::endl; | |
151 | #endif // __MINGW32__ | |
152 | ||
153 | message << "\n STL " << BOOST_STDLIB; | |
154 | message << "\n Boost version " << BOOST_VERSION / 100000 << "." << BOOST_VERSION / 100 % 1000 << "." << BOOST_VERSION % 100; | |
155 | ||
156 | #ifdef BOOST_MATH_TEST_MULTIPRECISION | |
157 | message << "\nBOOST_MATH_TEST_MULTIPRECISION defined for multiprecision tests. " << std::endl; | |
158 | #else | |
159 | message << "\nBOOST_MATH_TEST_MULTIPRECISION not defined so NO multiprecision tests. " << std::endl; | |
160 | #endif // BOOST_MATH_TEST_MULTIPRECISION | |
161 | ||
162 | #ifdef BOOST_HAS_FLOAT128 | |
163 | message << "BOOST_HAS_FLOAT128 is defined." << std::endl; | |
164 | #endif // ifdef BOOST_HAS_FLOAT128 | |
165 | ||
166 | message << std::endl; | |
167 | return message.str(); | |
168 | } // std::string show_versions() | |
169 | ||
170 | ||
171 | template <class T> | |
172 | void wolfram_test_moderate_values() | |
173 | { | |
174 | // | |
175 | // Spots of moderate value http://www.wolframalpha.com/input/?i=TABLE%5B%5BN%5B-1%2Fe%2Bi,+50%5D,+N%5BLambertW%5B-1%2Fe%2Bi%5D,+50%5D%5D,+%7Bi,+1%2F8,+6,+1%2F8%7D%5D | |
176 | // | |
1e59de90 | 177 | static const std::array<std::array<typename table_type<T>::type, 2>, 96/2> wolfram_test_small_neg = |
92f5a8d4 TL |
178 | {{ |
179 | {{ SC_(-0.24287944117144232159552377016146086744581113103177), SC_(-0.34187241316000572901412382650748493957063539755395) }},{{ SC_(-0.11787944117144232159552377016146086744581113103177), SC_(-0.13490446826612135454875992607636577833255418182633) }},{{ SC_(0.0071205588285576784044762298385391325541888689682322), SC_(0.0070703912528860797819274709355398032954165697080076) }},{{ SC_(0.13212055882855767840447622983853913255418886896823), SC_(0.11747650174894814471295063763686399700941650918302) }},{{ SC_(0.25712055882855767840447622983853913255418886896823), SC_(0.20869089404810562424547046857454995304964242368484) }},{{ SC_(0.38212055882855767840447622983853913255418886896823), SC_(0.28683366713002653952708635029764106993377156175310) }},{{ SC_(0.50712055882855767840447622983853913255418886896823), SC_(0.35542749308004931507852679571061486656821523044053) }},{{ SC_(0.63212055882855767840447622983853913255418886896823), SC_(0.41670399881776590750659327292575356285757792776250) }},{{ SC_(0.75712055882855767840447622983853913255418886896823), SC_(0.47217430075943420437939326812963066971059146681283) }},{{ SC_(0.88212055882855767840447622983853913255418886896823), SC_(0.52291321715862065064992942239384690347359852107504) }},{{ SC_(1.0071205588285576784044762298385391325541888689682), SC_(0.56971477154593975582335630229323210831843899740884) }},{{ SC_(1.1321205588285576784044762298385391325541888689682), SC_(0.61318350578224462394572352964726524514921241969798) }},{{ SC_(1.2571205588285576784044762298385391325541888689682), SC_(0.65379115237566259933564436658873734121781110980034) }},{{ SC_(1.3821205588285576784044762298385391325541888689682), SC_(0.69191341320406026236753559968630177636780741203666) }},{{ SC_(1.5071205588285576784044762298385391325541888689682), SC_(0.72785472286747598788295903283683432537852776142064) }},{{ SC_(1.6321205588285576784044762298385391325541888689682), SC_(0.76186544538805130363636977458614856100481979440639) }},{{ SC_(1.7571205588285576784044762298385391325541888689682), SC_(0.79415413501531119849043049331889268136479923750037) }},{{ SC_(1.8821205588285576784044762298385391325541888689682), SC_(0.82489647878345700122288701550494847447982817483512) }},{{ SC_(2.0071205588285576784044762298385391325541888689682), SC_(0.85424194939386899439722948096520865643710851410970) }},{{ SC_(2.1321205588285576784044762298385391325541888689682), SC_(0.88231884173371311472940735780441644004275449741412) }},{{ SC_(2.2571205588285576784044762298385391325541888689682), SC_(0.90923814516532488963517314558961057510689871415824) }},{{ SC_(2.3821205588285576784044762298385391325541888689682), SC_(0.93509656212104191797135657485515114635876341802516) }},{{ SC_(2.5071205588285576784044762298385391325541888689682), SC_(0.95997889061117906067636869169049106690165665554172) }},{{ SC_(2.6321205588285576784044762298385391325541888689682), SC_(0.98395992590529701946948066548039809917492328184099) }},{{ SC_(2.7571205588285576784044762298385391325541888689682), SC_(1.0071059939771381126732041109492705496242899774655) }},{{ SC_(2.8821205588285576784044762298385391325541888689682), SC_(1.0294761995723706229651673877352399077168142413723) }},{{ SC_(3.0071205588285576784044762298385391325541888689682), SC_(1.0511234507020167125769191146012321442040919222298) }},{{ SC_(3.1321205588285576784044762298385391325541888689682), SC_(1.0720953062286332723365148290552887215464891915069) }},{{ SC_(3.2571205588285576784044762298385391325541888689682), SC_(1.0924346821831089228990349517861599064007594751702) }},{{ SC_(3.3821205588285576784044762298385391325541888689682), SC_(1.1121804443118533629930276674418322662764569673766) }},{{ SC_(3.5071205588285576784044762298385391325541888689682), SC_(1.1313679082795201044696522785560810652358663683706) }},{{ SC_(3.6321205588285576784044762298385391325541888689682), SC_(1.1500292643692387775614691790201052907317404963905) }},{{ SC_(3.7571205588285576784044762298385391325541888689682), SC_(1.1681939400299161555212785901786587344721733034978) }},{{ SC_(3.8821205588285576784044762298385391325541888689682), SC_(1.1858889109341735194685896928615740804115521714257) }},{{ SC_(4.0071205588285576784044762298385391325541888689682), SC_(1.2031389691267953962289622785796365085402661808452) }},{{ SC_(4.1321205588285576784044762298385391325541888689682), SC_(1.2199669552139996161903252772502362264684476580522) }},{{ SC_(4.2571205588285576784044762298385391325541888689682), SC_(1.2363939602597347325278067608637615539794532870296) }},{{ SC_(4.3821205588285576784044762298385391325541888689682), SC_(1.2524395020361026107226019920575290018966524482736) }},{{ SC_(4.5071205588285576784044762298385391325541888689682), SC_(1.2681216794607666389159742215265331040507889789444) }},{{ SC_(4.6321205588285576784044762298385391325541888689682), SC_(1.2834573083995295018572263393035905604511320189369) }},{{ SC_(4.7571205588285576784044762298385391325541888689682), SC_(1.2984620414827281167361144981111712803667945033184) }},{{ SC_(4.8821205588285576784044762298385391325541888689682), SC_(1.3131504741533499076663954559108617687274731330916) }},{{ SC_(5.0071205588285576784044762298385391325541888689682), SC_(1.3275362388125116267199919229657120782894307415376) }},{{ SC_(5.1321205588285576784044762298385391325541888689682), SC_(1.3416320886383928057123774168081846145768561516693) }},{{ SC_(5.2571205588285576784044762298385391325541888689682), SC_(1.3554499724155634924134183248962114419200302481356) }},{{ SC_(5.3821205588285576784044762298385391325541888689682), SC_(1.3690011015132087699425938733927188719869603184010) }},{{ SC_(5.5071205588285576784044762298385391325541888689682), SC_(1.3822960099853765706075495327819109601506356054327) }},{{ SC_(5.6321205588285576784044762298385391325541888689682), SC_(1.3953446086279755263512146907828727538440007615239) }} | |
180 | }}; | |
181 | T tolerance = boost::math::tools::epsilon<T>() * 3; | |
182 | if (std::numeric_limits<T>::digits10 > 40) | |
183 | tolerance *= 4; // arbitrary precision types have lower accuracy on exp(z). | |
184 | for (unsigned i = 0; i < wolfram_test_small_neg.size(); ++i) | |
185 | { | |
186 | BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(T(wolfram_test_small_neg[i][0])), T(wolfram_test_small_neg[i][1]), tolerance); | |
187 | } | |
188 | } | |
189 | ||
190 | template <class T> | |
191 | void wolfram_test_small_pos() | |
192 | { | |
193 | // | |
194 | // Spots near zero and positive http://www.wolframalpha.com/input/?i=TABLE%5B%5BN%5BPi+*+10%5Ei,+50%5D,+N%5BLambertW%5BPi+*+10%5Ei%5D,+50%5D%5D,+%7Bi,+-25,+-1%7D%5D | |
195 | // | |
1e59de90 | 196 | static const std::array<std::array<typename table_type<T>::type, 2>, 25> wolfram_test_small_neg = |
92f5a8d4 TL |
197 | {{ |
198 | {{ SC_(3.1415926535897932384626433832795028841971693993751e-25), SC_(3.1415926535897932384626423963190627752613075159265e-25) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-24), SC_(3.1415926535897932384626335136751017948385505649306e-24) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-23), SC_(3.1415926535897932384625446872354919906109810591160e-23) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-22), SC_(3.1415926535897932384616564228393939483352864153693e-22) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-21), SC_(3.1415926535897932384527737788784135255783814177903e-21) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-20), SC_(3.1415926535897932383639473392686092980134754308784e-20) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-19), SC_(3.1415926535897932374756829431705670227788144495920e-19) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-18), SC_(3.1415926535897932285930389821901443118720934199487e-18) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-17), SC_(3.1415926535897931397665993723859213467937614455864e-17) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-16), SC_(3.1415926535897922515022032743441060948982739088029e-16) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-15), SC_(3.1415926535897833688582422939673934647266189937296e-15) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-14), SC_(3.1415926535896945424186324943442560413318839066091e-14) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-13), SC_(3.1415926535888062780225349125117696393347268403158e-13) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-12), SC_(3.1415926535799236340616005340756885831699803736331e-12) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-11), SC_(3.1415926534910971944564007385929431896486546006413e-11) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-10), SC_(3.1415926526028327988188016713407935109104110982749e-10) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-9), SC_(3.1415926437201888838826995251371676507148394412103e-9) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-8), SC_(3.1415925548937538785102994823474670579278874210259e-8) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-7), SC_(3.1415916666298182234172285804275105377159084331529e-7) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e-6), SC_(3.1415827840319013043684920305205420694740106954961e-6) }},{{ SC_(0.000031415926535897932384626433832795028841971693993751), SC_(0.000031414939621964641052828244109272729597989570861172) }},{{ SC_(0.00031415926535897932384626433832795028841971693993751), SC_(0.00031406061579842362125003023838529350597159230209458) }},{{ SC_(0.0031415926535897932384626433832795028841971693993751), SC_(0.0031317693004296877733926356188004473035977501714541) }},{{ SC_(0.031415926535897932384626433832795028841971693993751), SC_(0.030473027596269883517196555192955092247613270959259) }},{{ SC_(0.31415926535897932384626433832795028841971693993751), SC_(0.24571751376320572448656753973370462139374436325987) }} | |
199 | }}; | |
200 | T tolerance = boost::math::tools::epsilon<T>() * 3; | |
201 | if (std::numeric_limits<T>::digits10 > 40) | |
202 | tolerance *= 3; // arbitrary precision types have lower accuracy on exp(z). | |
203 | for (unsigned i = 0; i < wolfram_test_small_neg.size(); ++i) | |
204 | { | |
205 | BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(T(wolfram_test_small_neg[i][0])), T(wolfram_test_small_neg[i][1]), tolerance); | |
206 | } | |
207 | } | |
208 | ||
209 | template <class T> | |
210 | void wolfram_test_small_neg() | |
211 | { | |
212 | // | |
213 | // Spots near zero and negative http://www.wolframalpha.com/input/?i=TABLE%5B%5BN%5B-Pi+*+10%5Ei,+50%5D,+N%5BLambertW%5B-Pi+*+10%5Ei%5D,+50%5D%5D,+%7Bi,+-25,+-1%7D%5D | |
214 | // | |
1e59de90 | 215 | static const std::array<std::array<typename table_type<T>::type, 2>, 70/2> wolfram_test_small_neg = |
92f5a8d4 TL |
216 | {{ |
217 | {{ SC_(-3.1415926535897932384626433832795028841971693993751e-25), SC_(-3.1415926535897932384626443702399429931330312828247e-25) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-24), SC_(-3.1415926535897932384626532528839039735557882339126e-24) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-23), SC_(-3.1415926535897932384627420793235137777833577489360e-23) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-22), SC_(-3.1415926535897932384636303437196118200590533135692e-22) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-21), SC_(-3.1415926535897932384725129876805922428160503997900e-21) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-20), SC_(-3.1415926535897932385613394272903964703901652508759e-20) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-19), SC_(-3.1415926535897932394496038233884387465457126495672e-19) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-18), SC_(-3.1415926535897932483322477843688615495410754197010e-18) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-17), SC_(-3.1415926535897933371586873941730937234835814431099e-17) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-16), SC_(-3.1415926535897942254230834922158298617964738845526e-16) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-15), SC_(-3.1415926535898031080670444726846311337086192655470e-15) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-14), SC_(-3.1415926535898919345066542815166327311524009447840e-14) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-13), SC_(-3.1415926535907801989027527842355365380542172227242e-13) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-12), SC_(-3.1415926535996628428637792513133580846848848572500e-12) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-11), SC_(-3.1415926536884892824781879109701525247983589696795e-11) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-10), SC_(-3.1415926545767536790366733956272068630669876574730e-10) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-9), SC_(-3.1415926634593976860614172823213018318134944055260e-9) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-8), SC_(-3.1415927522858419002979913741894684038594384671969e-8) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-7), SC_(-3.1415936405506984418084674995072645049396296346958e-7) }},{{ SC_(-3.1415926535897932384626433832795028841971693993751e-6), SC_(-3.1416025232407040026008819016148803316716797067967e-6) }},{{ SC_(-0.000031415926535897932384626433832795028841971693993751), SC_(-0.000031416913542850054076094590477471913042739704497976) }},{{ SC_(-0.00031415926535897932384626433832795028841971693993751), SC_(-0.00031425800793839694440655801311183879569843264709852) }},{{ SC_(-0.0031415926535897932384626433832795028841971693993751), SC_(-0.0031515090287677856656576839914749012339811781712486) }},{{ SC_(-0.031415926535897932384626433832795028841971693993751), SC_(-0.032452164493239992272463616095775075564894751832128) }},{{ SC_(-0.31415926535897932384626433832795028841971693993751), SC_(-0.53804834513759287053587977755877044660611017981968) }}, | |
218 | {{ SC_(-0.090099009900990099009900990099009900990099009900990), SC_(-0.099527797075226962190621767732039397602197803169897)}},{{ SC_(-0.080198019801980198019801980198019801980198019801980), SC_(-0.087534530933383521242151071722737877728489741787814) }},{{ SC_(-0.070297029702970297029702970297029702970297029702970), SC_(-0.075835379000403488962496062196568904002201151736290) }},{{ SC_(-0.060396039603960396039603960396039603960396039603960), SC_(-0.064414449758822413858363348099340678962612835311800) }},{{ SC_(-0.050495049504950495049504950495049504950495049504950), SC_(-0.053257171600878093079366736202964706966166164696873) }},{{ SC_(-0.040594059405940594059405940594059405940594059405941), SC_(-0.042350146588050412657332988380168720859403591863698) }},{{ SC_(-0.030693069306930693069306930693069306930693069306931), SC_(-0.031681024260949098136757222042165581145138786336298) }},{{ SC_(-0.020792079207920792079207920792079207920792079207921), SC_(-0.021238392251213645736199359110665662967213312773617) }},{{ SC_(-0.010891089108910891089108910891089108910891089108911), SC_(-0.011011681049909946810068329378571761407667575030714) }},{{ SC_(-0.00099009900990099009900990099009900990099009900990099), SC_(-0.00099108076440319890968631186785975507712384928918616) }} | |
219 | }}; | |
220 | T tolerance = boost::math::tools::epsilon<T>() * 3; | |
221 | if (std::numeric_limits<T>::digits10 > 40) | |
222 | tolerance *= 3; // arbitrary precision types have lower accuracy on exp(z). | |
223 | for (unsigned i = 0; i < wolfram_test_small_neg.size(); ++i) | |
224 | { | |
225 | BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(T(wolfram_test_small_neg[i][0])), T(wolfram_test_small_neg[i][1]), tolerance); | |
226 | } | |
227 | } | |
228 | ||
229 | template <class T> | |
1e59de90 | 230 | void wolfram_test_large(const std::true_type&) |
92f5a8d4 TL |
231 | { |
232 | // | |
233 | // Spots near the singularity from http://www.wolframalpha.com/input/?i=TABLE%5B%5BN%5B-1%2Fe%2B2%5E-i,+50%5D,+N%5BLambertW%5B-1%2Fe+%2B+2%5E-i%5D,+50%5D%5D,+%7Bi,+2,+40%7D%5D | |
234 | // | |
1e59de90 | 235 | static const std::array<std::array<typename table_type<T>::type, 2>, 28/2> wolfram_test_large_data = |
92f5a8d4 TL |
236 | { { |
237 | {{ SC_(3.1415926535897932384626433832795028841971693993751e350), SC_(800.36444525326526998205084284403447902093784176640) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e400), SC_(915.35945025352715923124904626896745356022974283730) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e450), SC_(1030.3703481552571717312484086444052442055003737018) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e500), SC_(1145.3937726197879355969554296951287620979399652268) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e550), SC_(1260.4273249433458391941776841900870933799293511610) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e600), SC_(1375.4692354682341092954911299903937009237749971748) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e650), SC_(1490.5181612342761763990969379122584268166707632003) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e700), SC_(1605.5730589637597079362569020729894833435943718597) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e750), SC_(1720.6331020467166402802313799793443913873949058922) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e800), SC_(1835.6976244160526737141293452999638879204852786698) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e850), SC_(1950.7660814940759743605616247252782614446819652848) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e900), SC_(2065.8380223354646200773160641407055989098916114637) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e950), SC_(2180.9130693229593212006354812037286740424563145700) }},{{ SC_(3.1415926535897932384626433832795028841971693993751e1000), SC_(2295.9909030845346718801238821248991904602625884450) }} | |
238 | } }; | |
239 | T tolerance = boost::math::tools::epsilon<T>() * 3; | |
240 | if (std::numeric_limits<T>::digits10 > 40) | |
241 | tolerance *= 3; // arbitrary precision types have lower accuracy on exp(z). | |
242 | for (unsigned i = 0; i < wolfram_test_large_data.size(); ++i) | |
243 | { | |
244 | BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(T(wolfram_test_large_data[i][0])), T(wolfram_test_large_data[i][1]), tolerance); | |
245 | } | |
246 | } | |
247 | template <class T> | |
1e59de90 | 248 | void wolfram_test_large(const std::false_type&){} |
92f5a8d4 TL |
249 | |
250 | template <class T> | |
251 | void wolfram_test_large() | |
252 | { | |
1e59de90 | 253 | wolfram_test_large<T>(std::integral_constant<bool, (std::numeric_limits<T>::max_exponent10 > 1000)>()); |
92f5a8d4 TL |
254 | } |
255 | ||
256 | ||
257 | template <class T> | |
258 | void wolfram_test_near_singularity() | |
259 | { | |
260 | // | |
261 | // Spots near the singularity from http://www.wolframalpha.com/input/?i=TABLE%5B%5BN%5B-1%2Fe%2B2%5E-i,+50%5D,+N%5BLambertW%5B-1%2Fe+%2B+2%5E-i%5D,+50%5D%5D,+%7Bi,+2,+40%7D%5D | |
262 | // | |
1e59de90 | 263 | static const std::array<std::array<typename table_type<T>::type, 2>, 39> wolfram_test_near_singularity_data = |
92f5a8d4 TL |
264 | {{ |
265 | { { SC_(-0.11787944117144233402427744294982403516769409179688), SC_(-0.13490446826612137099065142885543349308605449591189) } },{ { SC_(-0.24287944117144233402427744294982403516769409179688), SC_(-0.34187241316000575559631565516533717918703951393828) } },{ { SC_(-0.30537944117144233402427744294982403516769409179688), SC_(-0.50704532478540670242736394530166187052909039079642) } },{ { SC_(-0.33662944117144233402427744294982403516769409179688), SC_(-0.63562321628494791544895212508757067989859372121549) } },{ { SC_(-0.35225444117144233402427744294982403516769409179688), SC_(-0.73357201771558852140844624841371893543359405991894) } },{ { SC_(-0.36006694117144233402427744294982403516769409179688), SC_(-0.80685912552602238275976720505076149562188136941981) } },{ { SC_(-0.36397319117144233402427744294982403516769409179688), SC_(-0.86091151614390373770305184939107560322835214525382) } },{ { SC_(-0.36592631617144233402427744294982403516769409179688), SC_(-0.90033567669608907987528169545609510444951296636737) } },{ { SC_(-0.36690287867144233402427744294982403516769409179688), SC_(-0.92884889586304130900291705545970353898661233095513) } },{ { SC_(-0.36739115992144233402427744294982403516769409179688), SC_(-0.94934196763921122756108351994184213101752011076782) } },{ { SC_(-0.36763530054644233402427744294982403516769409179688), SC_(-0.96400324129495105632485735566132352543383271582526) } },{ { SC_(-0.36775737085894233402427744294982403516769409179688), SC_(-0.97445736712728703357755243595334553847237474201138) } },{ { SC_(-0.36781840601519233402427744294982403516769409179688), SC_(-0.98189372378619472154195350108189165241865132390473) } },{ { SC_(-0.36784892359331733402427744294982403516769409179688), SC_(-0.98717434434269671591894280580432721487757138768109) } },{ { SC_(-0.36786418238237983402427744294982403516769409179688), SC_(-0.99091955260257317141206161906086819616043312707614) } },{ { SC_(-0.36787181177691108402427744294982403516769409179688), SC_(-0.99357346775773151586057357459040504547191256911173) } },{ { SC_(-0.36787562647417670902427744294982403516769409179688), SC_(-0.99545290640175819861266174073519228782773422561472) } },{ { SC_(-0.36787753382280952152427744294982403516769409179688), SC_(-0.99678329264937600678258333756796350065436689760936) } },{ { SC_(-0.36787848749712592777427744294982403516769409179688), SC_(-0.99772473035978895659981485126201758865515569761514) } },{ { SC_(-0.36787896433428413089927744294982403516769409179688), SC_(-0.99839078411548014765525278348680286544429555739338) } },{ { SC_(-0.36787920275286323246177744294982403516769409179688), SC_(-0.99886193379608135520603487963907992157933985302350) } },{ { SC_(-0.36787932196215278324302744294982403516769409179688), SC_(-0.99919517626703684624524893082905669989578841060892) } },{ { SC_(-0.36787938156679755863365244294982403516769409179688), SC_(-0.99943085896775657378245957087668418410735469441835) } },{ { SC_(-0.36787941136911994632896494294982403516769409179688), SC_(-0.99959753415605033951327478977234592072050509074480) } },{ { SC_(-0.36787942627028114017662119294982403516769409179688), SC_(-0.99971540249082798050505534900918173321899800190957) } },{ { SC_(-0.36787943372086173710044931794982403516769409179688), SC_(-0.99979875358003464529770521637722571161846456343102) } },{ { SC_(-0.36787943744615203556236338044982403516769409179688), SC_(-0.99985769449598686744630754715710430111838645655608) } },{ { SC_(-0.36787943930879718479332041169982403516769409179688), SC_(-0.99989937341527312969776294577792175610005161268265) } },{ { SC_(-0.36787944024011975940879892732482403516769409179688), SC_(-0.99992884556078314715423832743355922518662235135757) } },{ { SC_(-0.36787944070578104671653818513732403516769409179688), SC_(-0.99994968586433278794146581248117772412549843583586) } },{ { SC_(-0.36787944093861169037040781404357403516769409179688), SC_(-0.99996442235919152892644019456912452486892832990114) } },{ { SC_(-0.36787944105502701219734262849669903516769409179688), SC_(-0.99997484272221444495021480907850566954322542216868) } },{ { SC_(-0.36787944111323467311081003572326153516769409179688), SC_(-0.99998221107553951227244139186618591264285119372063) } },{ { SC_(-0.36787944114233850356754373933654278516769409179688), SC_(-0.99998742131038091608107093454795869661238860012568) } },{ { SC_(-0.36787944115689041879591059114318341016769409179688), SC_(-0.99999110551424805741455916942650424910940130482916) } },{ { SC_(-0.36787944116416637641009401704650372266769409179688), SC_(-0.99999371064603396347995131962984747427523504609782) } },{ { SC_(-0.36787944116780435521718572999816387891769409179688), SC_(-0.99999555275622895023796382943893319302015254415029) } },{ { SC_(-0.36787944116962334462073158647399395704269409179688), SC_(-0.99999685532777825691586263781552103878671869687024) } },{ { SC_(-0.36787944117053283932250451471190899610519409179688), SC_(-0.99999777638786151731498560321162974199505119200634) } } | |
266 | }}; | |
267 | T tolerance = boost::math::tools::epsilon<T>() * 3; | |
268 | if (boost::math::tools::epsilon<T>() <= boost::math::tools::epsilon<long double>()) | |
269 | tolerance *= 5e5; | |
270 | T endpoint = -boost::math::constants::exp_minus_one<T>(); | |
271 | for (unsigned i = 0; i < wolfram_test_near_singularity_data.size(); ++i) | |
272 | { | |
273 | if (wolfram_test_near_singularity_data[i][0] <= endpoint) | |
274 | break; | |
275 | else | |
276 | BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(T(wolfram_test_near_singularity_data[i][0])), T(wolfram_test_near_singularity_data[i][1]), tolerance); | |
277 | } | |
278 | } | |
279 | ||
280 | template <> | |
281 | void wolfram_test_near_singularity<float>() | |
282 | { | |
283 | // | |
284 | // Spot values near the singularity with inputs truncated to float precision, | |
285 | // from http://www.wolframalpha.com/input/?i=TABLE%5B%5BN%5BROUND%5B-1%2Fe%2B2%5E-i,+2%5E-23%5D,+50%5D,+N%5BLambertW%5BROUND%5B-1%2Fe+%2B+2%5E-i,+2%5E-23%5D%5D,+50%5D%5D,+%7Bi,+2,+40%7D%5D | |
286 | // | |
1e59de90 | 287 | static const std::array<std::array<float, 2>, 39> wolfram_test_near_singularity_data = |
92f5a8d4 TL |
288 | {{ |
289 | {{ -0.11787939071655273437500000000000000000000000000000f, -0.13490440151978599948261696847702203722148729212591f }},{{ -0.24287939071655273437500000000000000000000000000000f, -0.34187230524883404685074938529655332889057132590877f }},{{ -0.30537939071655273437500000000000000000000000000000f, -0.50704515484245965628066570100405225451296978841169f }},{{ -0.33662939071655273437500000000000000000000000000000f, -0.63562295482810970976475066480034941107064440641758f }},{{ -0.35225439071655273437500000000000000000000000000000f, -0.73357162334066102207977288738307124189083069773180f }},{{ -0.36006689071655273437500000000000000000000000000000f, -0.80685854013946199386910756662972252220827924037205f }},{{ -0.36397314071655273437500000000000000000000000000000f, -0.86091065811941702413570870801021404654934249886505f }},{{ -0.36592626571655273437500000000000000000000000000000f, -0.90033443111682454984393817004965279949925483847744f }},{{ -0.36690282821655273437500000000000000000000000000000f, -0.92884710067602836873486989954484681592392882968841f }},{{ -0.36739110946655273437500000000000000000000000000000f, -0.94933939406123900376318336910404763737960907662666f }},{{ -0.36763525009155273437500000000000000000000000000000f, -0.96399956611859464483214118051190513364901860207328f }},{{ -0.36775732040405273437500000000000000000000000000000f, -0.97445213361280651797731195324654593603807971082292f }},{{ -0.36781835556030273437500000000000000000000000000000f, -0.98188628650256330812037232517657284107351472091741f }},{{ -0.36784887313842773437500000000000000000000000000000f, -0.98716379155663346207408852364078406478772014890806f }},{{ -0.36786413192749023437500000000000000000000000000000f, -0.99090459761086986284393759319956676727684106186028f }},{{ -0.36787176132202148437500000000000000000000000000000f, -0.99355229825129408828026714426677096743753950457546f }},{{ -0.36787557601928710937500000000000000000000000000000f, -0.99542297991285328482403963994064328331346049089419f }},{{ -0.36787748336791992187500000000000000000000000000000f, -0.99674107062291256263133271694520294422529881114769f }},{{ -0.36787843704223632812500000000000000000000000000000f, -0.99766536478294767461296564658785293377699068226332f }},{{ -0.36787891387939453125000000000000000000000000000000f, -0.99830783438342654552199009076049244789994050996944f }},{{ -0.36787915229797363281250000000000000000000000000000f, -0.99874733565614076859582844941545958416543067187493f }},{{ -0.36787927150726318359375000000000000000000000000000f, -0.99903989590053869025356285499889881633845057984872f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }},{{ -0.36787939071655273437500000000000000000000000000000f, -0.99947635367299698033494423493356278945921228277354f }} | |
290 | }}; | |
291 | float tolerance = boost::math::tools::epsilon<float>() * 16; | |
292 | float endpoint = -boost::math::constants::exp_minus_one<float>(); | |
293 | for (unsigned i = 0; i < wolfram_test_near_singularity_data.size(); ++i) | |
294 | { | |
295 | if (wolfram_test_near_singularity_data[i][0] <= endpoint) | |
296 | break; | |
297 | else | |
298 | BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(wolfram_test_near_singularity_data[i][0]), wolfram_test_near_singularity_data[i][1], tolerance); | |
299 | } | |
300 | } | |
301 | ||
302 | template <> | |
303 | void wolfram_test_near_singularity<double>() | |
304 | { | |
305 | // | |
306 | // Spot values near the singularity with inputs truncated to double precision, | |
307 | // from http://www.wolframalpha.com/input/?i=TABLE%5B%5BN%5BROUND%5B-1%2Fe%2B2%5E-i,+2%5E-23%5D,+50%5D,+N%5BLambertW%5BROUND%5B-1%2Fe+%2B+2%5E-i,+2%5E-23%5D%5D,+50%5D%5D,+%7Bi,+2,+40%7D%5D | |
308 | // | |
1e59de90 | 309 | static const std::array<std::array<double, 2>, 39> wolfram_test_near_singularity_data = |
92f5a8d4 TL |
310 | {{ |
311 | {{ -0.11787944117144233402427744294982403516769409179688, -0.13490446826612137099065142885543349308605449591189 }},{{ -0.24287944117144233402427744294982403516769409179688, -0.34187241316000575559631565516533717918703951393828 }},{{ -0.30537944117144233402427744294982403516769409179688, -0.50704532478540670242736394530166187052909039079642 }},{{ -0.33662944117144233402427744294982403516769409179688, -0.63562321628494791544895212508757067989859372121549 }},{{ -0.35225444117144233402427744294982403516769409179688, -0.73357201771558852140844624841371893543359405991894 }},{{ -0.36006694117144233402427744294982403516769409179688, -0.80685912552602238275976720505076149562188136941981 }},{{ -0.36397319117144233402427744294982403516769409179688, -0.86091151614390373770305184939107560322835214525382 }},{{ -0.36592631617144233402427744294982403516769409179688, -0.90033567669608907987528169545609510444951296636737 }},{{ -0.36690287867144233402427744294982403516769409179688, -0.92884889586304130900291705545970353898661233095513 }},{{ -0.36739115992144233402427744294982403516769409179688, -0.94934196763921122756108351994184213101752011076782 }},{{ -0.36763530054644233402427744294982403516769409179688, -0.96400324129495105632485735566132352543383271582526 }},{{ -0.36775737085894233402427744294982403516769409179688, -0.97445736712728703357755243595334553847237474201138 }},{{ -0.36781840601519233402427744294982403516769409179688, -0.98189372378619472154195350108189165241865132390473 }},{{ -0.36784892359331733402427744294982403516769409179688, -0.98717434434269671591894280580432721487757138768109 }},{{ -0.36786418238237983402427744294982403516769409179688, -0.99091955260257317141206161906086819616043312707614 }},{{ -0.36787181177691108402427744294982403516769409179688, -0.99357346775773151586057357459040504547191256911173 }},{{ -0.36787562647417670902427744294982403516769409179688, -0.99545290640175819861266174073519228782773422561472 }},{{ -0.36787753382280952152427744294982403516769409179688, -0.99678329264937600678258333756796350065436689760936 }},{{ -0.36787848749712592777427744294982403516769409179688, -0.99772473035978895659981485126201758865515569761514 }},{{ -0.36787896433428413089927744294982403516769409179688, -0.99839078411548014765525278348680286544429555739338 }},{{ -0.36787920275286323246177744294982403516769409179688, -0.99886193379608135520603487963907992157933985302350 }},{{ -0.36787932196215278324302744294982403516769409179688, -0.99919517626703684624524893082905669989578841060892 }},{{ -0.36787938156679755863365244294982403516769409179688, -0.99943085896775657378245957087668418410735469441835 }},{{ -0.36787941136911994632896494294982403516769409179688, -0.99959753415605033951327478977234592072050509074480 }},{{ -0.36787942627028114017662119294982403516769409179688, -0.99971540249082798050505534900918173321899800190957 }},{{ -0.36787943372086173710044931794982403516769409179688, -0.99979875358003464529770521637722571161846456343102 }},{{ -0.36787943744615203556236338044982403516769409179688, -0.99985769449598686744630754715710430111838645655608 }},{{ -0.36787943930879718479332041169982403516769409179688, -0.99989937341527312969776294577792175610005161268265 }},{{ -0.36787944024011975940879892732482403516769409179688, -0.99992884556078314715423832743355922518662235135757 }},{{ -0.36787944070578104671653818513732403516769409179688, -0.99994968586433278794146581248117772412549843583586 }},{{ -0.36787944093861169037040781404357403516769409179688, -0.99996442235919152892644019456912452486892832990114 }},{{ -0.36787944105502701219734262849669903516769409179688, -0.99997484272221444495021480907850566954322542216868 }},{{ -0.36787944111323467311081003572326153516769409179688, -0.99998221107553951227244139186618591264285119372063 }},{{ -0.36787944114233850356754373933654278516769409179688, -0.99998742131038091608107093454795869661238860012568 }},{{ -0.36787944115689041879591059114318341016769409179688, -0.99999110551424805741455916942650424910940130482916 }},{{ -0.36787944116416637641009401704650372266769409179688, -0.99999371064603396347995131962984747427523504609782 }},{{ -0.36787944116780435521718572999816387891769409179688, -0.99999555275622895023796382943893319302015254415029 }},{{ -0.36787944116962334462073158647399395704269409179688, -0.99999685532777825691586263781552103878671869687024 }},{{ -0.36787944117053283932250451471190899610519409179688, -0.99999777638786151731498560321162974199505119200634 }} | |
312 | }}; | |
313 | double tolerance = boost::math::tools::epsilon<double>() * 5; | |
314 | if (std::numeric_limits<double>::digits >= std::numeric_limits<long double>::digits) | |
315 | tolerance *= 1e5; | |
316 | else if (std::numeric_limits<double>::digits * 2 >= std::numeric_limits<long double>::digits) | |
317 | tolerance *= 5e4; | |
318 | double endpoint = -boost::math::constants::exp_minus_one<double>(); | |
319 | for (unsigned i = 0; i < wolfram_test_near_singularity_data.size(); ++i) | |
320 | { | |
321 | if (wolfram_test_near_singularity_data[i][0] <= endpoint) | |
322 | break; | |
323 | else | |
324 | BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(wolfram_test_near_singularity_data[i][0]), wolfram_test_near_singularity_data[i][1], tolerance); | |
325 | } | |
326 | } | |
327 | ||
328 | template <class RealType> | |
329 | void test_spots(RealType) | |
330 | { | |
331 | // (Unused Parameter value, arbitrarily zero, only communicates the floating point type). | |
332 | // test_spots(0.F); test_spots(0.); test_spots(0.L); | |
333 | ||
334 | using boost::math::lambert_w0; | |
335 | using boost::math::lambert_wm1; | |
336 | using boost::math::constants::exp_minus_one; | |
337 | using boost::math::constants::e; | |
338 | using boost::math::policies::policy; | |
339 | ||
340 | /* Example of an exception-free 'ignore_all' policy (possibly ill-advised?). | |
341 | */ | |
342 | typedef policy < | |
343 | boost::math::policies::domain_error<boost::math::policies::ignore_error>, | |
344 | boost::math::policies::overflow_error<boost::math::policies::ignore_error>, | |
345 | boost::math::policies::underflow_error<boost::math::policies::ignore_error>, | |
346 | boost::math::policies::denorm_error<boost::math::policies::ignore_error>, | |
347 | boost::math::policies::pole_error<boost::math::policies::ignore_error>, | |
348 | boost::math::policies::evaluation_error<boost::math::policies::ignore_error> | |
349 | > ignore_all_policy; | |
350 | ||
351 | // Test some bad parameters to the function, with default policy and also with ignore_all policy. | |
352 | #ifndef BOOST_NO_EXCEPTIONS | |
353 | BOOST_CHECK_THROW(lambert_w0<RealType>(-1.), std::domain_error); | |
354 | BOOST_CHECK_THROW(lambert_wm1<RealType>(-1.), std::domain_error); | |
355 | if (std::numeric_limits<RealType>::has_quiet_NaN) | |
356 | { | |
357 | BOOST_CHECK_THROW(lambert_w0<RealType>(std::numeric_limits<RealType>::quiet_NaN()), std::domain_error); // Would be NaN. | |
358 | //BOOST_CHECK_EQUAL(lambert_w0<RealType>(std::numeric_limits<RealType>::quiet_NaN(), ignore_all_policy()), std::numeric_limits<RealType>::quiet_NaN()); // Should be NaN. | |
359 | // Fails as NaN != NaN by definition. | |
360 | BOOST_CHECK(boost::math::isnan(lambert_w0<RealType>(std::numeric_limits<RealType>::quiet_NaN(), ignore_all_policy()))); | |
361 | //BOOST_MATH_CHECK_EQUAL(boost::math::lambert_w0<RealType>(std::numeric_limits<RealType>::infinity(), ignore_all_policy()), std::numeric_limits<RealType::infinity()); // infinity. | |
362 | } | |
363 | ||
364 | // BOOST_CHECK_THROW(lambert_w0<RealType>(std::numeric_limits<RealType>::infinity()), std::domain_error); // Was if infinity should throw, now infinity. | |
365 | BOOST_CHECK_THROW(lambert_w0<RealType>(-static_cast<RealType>(0.4)), std::domain_error); // Would be complex. | |
366 | ||
367 | #else // No exceptions, so set policy to ignore and check result is NaN. | |
368 | BOOST_MATH_CHECK_EQUAL(boost::math::lambert_w0<RealType>(std::numeric_limits<RealType>::quiet_NaN(), ignore_all_policy()), std::numeric_limits<RealType::quiet_NaN()); // NaN. | |
369 | BOOST_MATH_CHECK_EQUAL(boost::math::lambert_w0<RealType>(std::numeric_limits<RealType>::infinity(), ignore_all_policy()), std::numeric_limits<RealType::infinity()); // infinity. | |
370 | BOOST_MATH_CHECK_EQUAL(boost::math::lambert_w0<RealType>(std::numeric_limits<RealType>::infinity(), ignore_all_policy()), std::numeric_limits<RealType::infinity()); // infinity. | |
371 | #endif | |
372 | ||
373 | std::cout << "\nTesting type " << typeid(RealType).name() << std::endl; | |
374 | int epsilons = 2; | |
375 | if (std::numeric_limits<RealType>::digits > 53) | |
376 | { // Multiprecision types. | |
377 | epsilons *= 8; // (Perhaps needed because need slightly longer (55) reference values?). | |
378 | } | |
379 | RealType tolerance = boost::math::tools::epsilon<RealType>() * epsilons; // 2 eps as a fraction. | |
380 | std::cout << "Tolerance " << epsilons << " * epsilon == " << tolerance << std::endl; | |
381 | #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS | |
382 | std::cout << "Precision " << std::numeric_limits<RealType>::digits10 << " decimal digits, max_digits10 = " << std::numeric_limits <RealType>::max_digits10<< std::endl; | |
383 | // std::cout.precision(std::numeric_limits<RealType>::digits10); | |
384 | std::cout.precision(std::numeric_limits <RealType>::max_digits10); | |
385 | #endif | |
386 | std::cout.setf(std::ios_base::showpoint); // show trailing significant zeros. | |
387 | std::cout << "-exp(-1) = " << -exp_minus_one<RealType>() << std::endl; | |
388 | ||
389 | wolfram_test_near_singularity<RealType>(); | |
390 | wolfram_test_large<RealType>(); | |
391 | wolfram_test_small_neg<RealType>(); | |
392 | wolfram_test_small_pos<RealType>(); | |
393 | wolfram_test_moderate_values<RealType>(); | |
394 | ||
395 | // Test at singularity. | |
396 | // RealType test_value = BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527); | |
397 | RealType singular_value = -exp_minus_one<RealType>(); | |
398 | // -exp(-1) = -0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527 | |
399 | // lambert_w0[-0.367879441171442321595523770161460867445811131031767834] == -1 | |
400 | // -0.36787945032119751 | |
401 | RealType minus_one_value = BOOST_MATH_TEST_VALUE(RealType, -1.); | |
402 | //std::cout << "singular_value " << singular_value << ", expected Lambert W = " << minus_one_value << std::endl; | |
403 | ||
404 | BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) = -0.367879450 = -1max | |
405 | lambert_w0(singular_value), | |
406 | minus_one_value, | |
407 | tolerance); // OK | |
408 | ||
409 | BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) ~= -0.367879450 == -1 | |
410 | lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527)), | |
411 | BOOST_MATH_TEST_VALUE(RealType, -1.), | |
412 | tolerance); | |
413 | ||
414 | BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) ~= -0.367879450 == -1 | |
415 | lambert_w0<RealType>(-exp_minus_one<RealType>()), | |
416 | BOOST_MATH_TEST_VALUE(RealType, -1.), | |
417 | tolerance); | |
418 | ||
419 | // Tests with some spot values computed using | |
420 | // https://www.wolframalpha.com/input | |
421 | // For example: N[lambert_w[1], 50] outputs: | |
422 | // 0.56714329040978387299996866221035554975381578718651 | |
423 | ||
424 | // At branch junction singularity. | |
425 | BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) ~= -0.367879450 == -1 | |
426 | lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527)), | |
427 | BOOST_MATH_TEST_VALUE(RealType, -1.), | |
428 | tolerance); | |
429 | ||
430 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.1)), | |
431 | BOOST_MATH_TEST_VALUE(RealType, 0.091276527160862264299895721423179568653119224051472), | |
432 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(0.2) | |
433 | tolerance); | |
434 | ||
435 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.2)), | |
436 | BOOST_MATH_TEST_VALUE(RealType, 0.16891597349910956511647490370581839872844691351073), | |
437 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(0.2) | |
438 | tolerance); | |
439 | ||
440 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.5)), | |
441 | BOOST_MATH_TEST_VALUE(RealType, 0.351733711249195826024909300929951065171464215517111804046), | |
442 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(0.5) | |
443 | tolerance); | |
444 | ||
445 | BOOST_CHECK_CLOSE_FRACTION( | |
446 | lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.)), | |
447 | BOOST_MATH_TEST_VALUE(RealType, 0.56714329040978387299996866221035554975381578718651), | |
448 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(1) | |
449 | tolerance); | |
450 | ||
451 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 2.)), | |
452 | BOOST_MATH_TEST_VALUE(RealType, 0.852605502013725491346472414695317466898453300151403508772), | |
453 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(2.) | |
454 | tolerance); | |
455 | ||
456 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 3.)), | |
457 | BOOST_MATH_TEST_VALUE(RealType, 1.049908894964039959988697070552897904589466943706341452932), | |
458 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(3.) | |
459 | tolerance); | |
460 | ||
461 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 5.)), | |
462 | BOOST_MATH_TEST_VALUE(RealType, 1.326724665242200223635099297758079660128793554638047479789), | |
463 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(0.5) | |
464 | tolerance); | |
465 | ||
466 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 6.)), | |
467 | BOOST_MATH_TEST_VALUE(RealType, 1.432404775898300311234078007212058694786434608804302025655), | |
468 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(6) | |
469 | tolerance); | |
470 | ||
471 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 100.)), | |
472 | BOOST_MATH_TEST_VALUE(RealType, 3.3856301402900501848882443645297268674916941701578), | |
473 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(100) | |
474 | tolerance); | |
475 | ||
476 | if (std::numeric_limits<RealType>::has_infinity) | |
477 | { | |
478 | BOOST_CHECK_THROW(lambert_w0(std::numeric_limits<RealType>::infinity()), std::overflow_error); // If should throw exception for infinity. | |
479 | //BOOST_CHECK_EQUAL(lambert_w0(std::numeric_limits<RealType>::infinity()), +std::numeric_limits<RealType>::infinity()); // message is: | |
480 | // Error in "test_types": class boost::exception_detail::clone_impl<struct boost::exception_detail::error_info_injector<class std::overflow_error> > : | |
481 | // Error in function boost::math::lambert_w0<RealType>(<RealType>) : Argument z is infinite! | |
482 | //BOOST_CHECK_EQUAL(lambert_w0(std::numeric_limits<RealType>::infinity()), +std::numeric_limits<RealType>::infinity()); // If infinity allowed. | |
483 | BOOST_CHECK_THROW(lambert_wm1(std::numeric_limits<RealType>::infinity()), std::domain_error); // Infinity NOT allowed at all (not an edge case). | |
484 | } | |
485 | if (std::numeric_limits<RealType>::has_quiet_NaN) | |
486 | { // Argument Z == NaN is always an throwable error for both branches. | |
487 | // BOOST_CHECK_EQUAL(lambert_w0(std::numeric_limits<RealType>::quiet_NaN()), +std::numeric_limits<RealType>::infinity()); // message is: | |
488 | // Error in function boost::math::lambert_w0<RealType>(<RealType>): Argument z is NaN! | |
489 | BOOST_CHECK_THROW(lambert_w0(std::numeric_limits<RealType>::quiet_NaN()), std::domain_error); | |
490 | BOOST_CHECK_THROW(lambert_wm1(std::numeric_limits<RealType>::quiet_NaN()), std::domain_error); | |
491 | } | |
492 | ||
493 | // denorm - but might be == min or zero? | |
494 | if (std::numeric_limits<RealType>::has_denorm == true) | |
495 | { // Might also return infinity like z == 0? | |
496 | BOOST_CHECK_THROW(lambert_wm1(std::numeric_limits<RealType>::denorm_min()), std::overflow_error); | |
497 | } | |
498 | ||
499 | // Tests of Lambert W-1 branch. | |
500 | BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) ~= -0.367879450 == -1 at the singularity branch point. | |
501 | lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527)), | |
502 | BOOST_MATH_TEST_VALUE(RealType, -1.), | |
503 | tolerance); | |
504 | ||
505 | // Near singularity and using series approximation. | |
506 | // N[productlog(-1, -0.36), 50] = -1.2227701339785059531429380734238623131735264411311 | |
507 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.36)), | |
508 | BOOST_MATH_TEST_VALUE(RealType, -1.2227701339785059531429380734238623131735264411311), | |
509 | 10 * tolerance); // tolerance OK for quad | |
510 | // -1.2227701339785059531429380734238623131735264411311 | |
511 | // -1.222770133978505953142938073423862313173526441131033 | |
512 | ||
513 | // Just using series approximation (switch at -0.35). | |
514 | // N[productlog(-0.351), 50] = -0.72398644140937651483634596143951001600417138085814 | |
515 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.351)), | |
516 | BOOST_MATH_TEST_VALUE(RealType, -0.72398644140937651483634596143951001600417138085814), | |
517 | // 2 * tolerance); // Note 2 * tolerance for PB fukushima | |
518 | // got -0.723986441409376931150560229265736446 without Halley | |
519 | // exp -0.72398644140937651483634596143951001 | |
520 | // got -0.72398644140937651483634596143951029 with Halley | |
521 | 10 * tolerance); // expect -0.72398644140937651 float -0.723987103 needs 10 * tolerance | |
522 | // 2 * tolerance is fine for double and up. | |
523 | // Float is OK | |
524 | ||
525 | // Same for W-1 branch | |
526 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.351)), | |
527 | BOOST_MATH_TEST_VALUE(RealType, -1.3385736984773431852492145715526995809854973408320), | |
528 | 10 * tolerance); // 2 tolerance OK for quad | |
529 | ||
530 | // Near singularity and NOT using series approximation (switch at -0.35) | |
531 | // N[productlog(-1, -0.34), 50] | |
532 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.34)), | |
533 | BOOST_MATH_TEST_VALUE(RealType, -1.4512014851325470735077533710339268100722032730024), | |
534 | 10 * tolerance); // tolerance OK for quad | |
535 | // | |
536 | ||
537 | // Decreasing z until near zero (small z) . | |
538 | //N[productlog(-1, -0.3), 50] = -1.7813370234216276119741702815127452608215583564545 | |
539 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.3)), | |
540 | BOOST_MATH_TEST_VALUE(RealType, -1.7813370234216276119741702815127452608215583564545), | |
541 | 2 * tolerance); | |
542 | // -1.78133702342162761197417028151274526082155835645446 | |
543 | ||
544 | //N[productlog(-1, -0.2), 50] = -2.5426413577735264242938061566618482901614749075294 | |
545 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.2)), | |
546 | BOOST_MATH_TEST_VALUE(RealType, -2.5426413577735264242938061566618482901614749075294), | |
547 | 2 * tolerance); | |
548 | ||
549 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.1)), | |
550 | BOOST_MATH_TEST_VALUE(RealType, -3.577152063957297218409391963511994880401796257793), | |
551 | tolerance); | |
552 | ||
553 | //N[productlog(-1, -0.01), 50] = -6.4727751243940046947410578927244880371043455902257 | |
554 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.01)), | |
555 | BOOST_MATH_TEST_VALUE(RealType, -6.4727751243940046947410578927244880371043455902257), | |
556 | tolerance); | |
557 | ||
558 | // N[productlog(-1, -0.001), 50] = -9.1180064704027401212583371820468142742704349737639 | |
559 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.001)), | |
560 | BOOST_MATH_TEST_VALUE(RealType, -9.1180064704027401212583371820468142742704349737639), | |
561 | tolerance); | |
562 | ||
563 | // N[productlog(-1, -0.000001), 50] = -16.626508901372473387706432163984684996461726803805 | |
564 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.000001)), | |
565 | BOOST_MATH_TEST_VALUE(RealType, -16.626508901372473387706432163984684996461726803805), | |
566 | tolerance); | |
567 | ||
568 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-12)), | |
569 | BOOST_MATH_TEST_VALUE(RealType, -31.067172842017230842039496250208586707880448763222), | |
570 | tolerance); | |
571 | ||
572 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-25)), | |
573 | BOOST_MATH_TEST_VALUE(RealType, -61.686695602074505366866968627049381352503620377944), | |
574 | tolerance); | |
575 | ||
576 | // z nearly too small. | |
577 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -2e-26)), | |
578 | BOOST_MATH_TEST_VALUE(RealType, -63.322302839923597803393585145387854867226970485197), | |
579 | tolerance* 2); | |
580 | ||
581 | // z very nearly too small. G(k=64) g[63] = -1.0264389699511303e-26 to using 1.027e-26 | |
582 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1.027e-26)), | |
583 | BOOST_MATH_TEST_VALUE(RealType, -63.999444896732265186957073549916026532499356695343), | |
584 | tolerance); | |
585 | // So -64 is the most negative value that can be determined using lookup. | |
586 | // N[productlog(-1, -1.0264389699511303 * 10^-26 ), 50] -63.999999999999997947255011093606206983577811736472 == -64 | |
587 | // G[k=64] = g[63] = -1.0264389699511303e-26 | |
588 | ||
589 | // z too small for G(k=64) g[63] = -1.0264389699511303e-26 to using 1.027e-26 | |
590 | // N[productlog(-1, -10 ^ -26), 50] = -31.067172842017230842039496250208586707880448763222 | |
591 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-26)), | |
592 | BOOST_MATH_TEST_VALUE(RealType, -64.026509628385889681156090340691637712441162092868), | |
593 | tolerance); // -64.0265121 | |
594 | ||
595 | if (std::numeric_limits<RealType>::has_infinity) | |
596 | { | |
597 | BOOST_CHECK_EQUAL(lambert_wm1(0), -std::numeric_limits<RealType>::infinity()); | |
598 | } | |
599 | if (std::numeric_limits<RealType>::has_quiet_NaN) | |
600 | { | |
601 | // BOOST_CHECK_EQUAL(lambert_w0(std::numeric_limits<RealType>::quiet_NaN()), +std::numeric_limits<RealType>::infinity()); // message is: | |
602 | // Error in function boost::math::lambert_w0<RealType>(<RealType>): Argument z is NaN! | |
603 | BOOST_CHECK_THROW(lambert_wm1(std::numeric_limits<RealType>::quiet_NaN()), std::domain_error); | |
604 | } | |
605 | ||
606 | // W0 Tests for too big and too small to use lookup table. | |
607 | // Exactly W = 64, not enough to be OK for lookup. | |
608 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 3.9904954117194348050619127737142206366920907815909119e+29)), | |
609 | BOOST_MATH_TEST_VALUE(RealType, 64.0), | |
610 | tolerance); | |
611 | ||
612 | // Just below z for F[64] | |
613 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 3.99045411719434e+29)), | |
614 | BOOST_MATH_TEST_VALUE(RealType, 63.999989810930513468726486827408823607175844852495), tolerance); | |
615 | // Fails for quad_float -1.22277013397850595265 | |
616 | // -1.22277013397850595319 | |
617 | ||
618 | // Just too big, so using log approx and Halley refinement. | |
619 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 4e+29)), | |
620 | BOOST_MATH_TEST_VALUE(RealType, 64.002342375637950350970694519073803643686041499677), | |
621 | tolerance); | |
622 | ||
623 | // Check at reduced precision. | |
624 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 4e+29), policy<digits2<11> >()), | |
625 | BOOST_MATH_TEST_VALUE(RealType, 64.002342375637950350970694519073803643686041499677), | |
626 | 0.00002); // 0.00001 fails. | |
627 | ||
628 | // Tests to ensure that all JM rational polynomials are being checked. | |
629 | ||
f67539c2 | 630 | // 1st polynomial if (z < 0.5) // 0.05 < z < 0.5 |
92f5a8d4 TL |
631 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.49)), |
632 | BOOST_MATH_TEST_VALUE(RealType, 0.3465058086974944293540338951489158955895910665452626949), | |
633 | tolerance); | |
634 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.051)), | |
635 | BOOST_MATH_TEST_VALUE(RealType, 0.04858156174600359264950777241723801201748517590507517888), | |
636 | tolerance); | |
637 | ||
f67539c2 | 638 | // 2st polynomial if 0.5 < z < 2 |
92f5a8d4 TL |
639 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.51)), |
640 | BOOST_MATH_TEST_VALUE(RealType, 0.3569144916935871518694242462560450385494399307379277704), | |
641 | tolerance); | |
642 | ||
643 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.9)), | |
644 | BOOST_MATH_TEST_VALUE(RealType, 0.8291763302658400337004358009672187071638421282477162293), | |
645 | tolerance); | |
646 | ||
647 | // 3rd polynomials 2 < z < 6 | |
648 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 2.1)), | |
649 | BOOST_MATH_TEST_VALUE(RealType, 0.8752187586805470099843211502166029752154384079916131962), | |
650 | tolerance); | |
651 | ||
652 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 5.9)), | |
653 | BOOST_MATH_TEST_VALUE(RealType, 1.422521411785098213935338853943459424120416844150520831), | |
654 | tolerance); | |
655 | ||
656 | // 4th polynomials 6 < z < 18 | |
657 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 6.1)), | |
658 | BOOST_MATH_TEST_VALUE(RealType, 1.442152194116056579987235881273412088690824214100254315), | |
659 | tolerance); | |
660 | ||
661 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 17.9)), | |
662 | BOOST_MATH_TEST_VALUE(RealType, 2.129100923757568114366514708174691237123820852409339147), | |
663 | tolerance); | |
664 | ||
665 | // 5th polynomials if (z < 9897.12905874) // 2.8 < log(z) < 9.2 | |
666 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 18.1)), | |
667 | BOOST_MATH_TEST_VALUE(RealType, 2.136665501382339778305178680563584563343639180897328666), | |
668 | tolerance); | |
669 | ||
670 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 9897.)), | |
671 | BOOST_MATH_TEST_VALUE(RealType, 7.222751047988674263127929506116648714752441161828893633), | |
672 | tolerance); | |
673 | ||
674 | // 6th polynomials if (z < 7.896296e+13) // 9.2 < log(z) <= 32 | |
675 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 9999.)), | |
676 | BOOST_MATH_TEST_VALUE(RealType, 7.231758181708737258902175236106030961433080976032516996), | |
677 | tolerance); | |
678 | ||
679 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 7.7e+13)), | |
680 | BOOST_MATH_TEST_VALUE(RealType, 28.62069643025822480911439831021393125282095606713326376), | |
681 | tolerance); | |
682 | ||
683 | // 7th polynomial // 32 < log(z) < 100 | |
684 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 8.0e+18)), | |
685 | BOOST_MATH_TEST_VALUE(RealType, 39.84107480517853176296156400093560722439428484537515586), | |
686 | tolerance); | |
687 | ||
688 | // Largest 32-bit float. (Larger values for other types tested using max()) | |
689 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.e38)), | |
690 | BOOST_MATH_TEST_VALUE(RealType, 83.07844821316409592720410446942538465411465113447713574), | |
691 | tolerance); | |
692 | ||
693 | // Using z small series function if z < 0.05 if (z < -0.051) -0.27 < z < -0.051 | |
694 | ||
695 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.28)), | |
696 | BOOST_MATH_TEST_VALUE(RealType, -0.4307588745271127579165306568413721388196459822705155385), | |
697 | tolerance); | |
698 | ||
699 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.25)), | |
700 | BOOST_MATH_TEST_VALUE(RealType, -0.3574029561813889030688111040559047533165905550760120436), | |
701 | tolerance); | |
702 | ||
703 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, +0.25)), | |
704 | BOOST_MATH_TEST_VALUE(RealType, 0.2038883547022401644431818313271398701493524772101596350), | |
705 | tolerance); | |
706 | ||
707 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.051)), // just above 0.05 cutoff. | |
708 | BOOST_MATH_TEST_VALUE(RealType, -0.05382002772543396036830469500362485089791914689728115249), | |
709 | tolerance * 4); | |
710 | ||
711 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.05)), // at cutoff. | |
712 | BOOST_MATH_TEST_VALUE(RealType, -0.05270598355154634795995650617915721289427674396592395160), | |
713 | tolerance * 8); | |
714 | ||
715 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.049)), // Just below cutoff. | |
716 | BOOST_MATH_TEST_VALUE(RealType, 0.04676143671340832342497289393737051868103596756298863555), | |
717 | tolerance * 4); | |
718 | ||
719 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.01)), | |
720 | BOOST_MATH_TEST_VALUE(RealType, 0.009901473843595011885336326816570107953627746494917415483), | |
721 | tolerance); | |
722 | ||
723 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.01)), | |
724 | BOOST_MATH_TEST_VALUE(RealType, -0.01010152719853875327292018767138623973670903993475235877), | |
725 | tolerance); | |
726 | ||
727 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.049)), | |
728 | BOOST_MATH_TEST_VALUE(RealType, -0.05159448479219405354564920228913331280713177046648170658), | |
729 | tolerance * 8); | |
730 | ||
731 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1e-6)), | |
732 | BOOST_MATH_TEST_VALUE(RealType, 9.999990000014999973333385416558666900096702096424344715e-7), | |
733 | tolerance); | |
734 | ||
735 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -1e-6)), | |
736 | BOOST_MATH_TEST_VALUE(RealType, -1.000001000001500002666671875010800023343107568372593753e-6), | |
737 | tolerance); | |
738 | ||
739 | // Near Smallest float. | |
740 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1e-38)), | |
741 | BOOST_MATH_TEST_VALUE(RealType, 9.99999999999999999999999999999999999990000000000000000e-39), | |
742 | tolerance); | |
743 | ||
744 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -1e-38)), | |
745 | BOOST_MATH_TEST_VALUE(RealType, -1.000000000000000000000000000000000000010000000000000000e-38), | |
746 | tolerance); | |
747 | ||
748 | // Similar 'too near zero' tests for W-1 branch. | |
749 | // lambert_wm1(-1.0264389699511283e-26) = -64.000000000000000 | |
750 | // Exactly z for W=-64 | |
751 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1.026438969951128225904695701851094643838952857740385870e-26)), | |
752 | BOOST_MATH_TEST_VALUE(RealType, -64.000000000000000000000000000000000000), | |
753 | 2 * tolerance); | |
754 | ||
755 | // Just more negative than G[64 max] = wm1zs[63] so can't use lookup table. | |
756 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1.5e-27)), | |
757 | BOOST_MATH_TEST_VALUE(RealType, -65.953279000145077719128800110134854577850889171784), | |
758 | tolerance); // -65.9532776 | |
759 | ||
760 | // Just less negative than G[64 max] = wm1zs[63] so can use lookup table. | |
761 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1.1e-26)), | |
762 | BOOST_MATH_TEST_VALUE(RealType, -63.929686062157630858625440758283127600360210072859), | |
763 | tolerance); | |
764 | ||
765 | // N[productlog(-1, -10 ^ -26), 50] = -31.067172842017230842039496250208586707880448763222 | |
766 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-26)), | |
767 | BOOST_MATH_TEST_VALUE(RealType, -64.026509628385889681156090340691637712441162092868), | |
768 | tolerance); | |
769 | ||
770 | // 1e-28 is too small | |
771 | // N[productlog(-1, -10 ^ -28), 50] = -31.067172842017230842039496250208586707880448763222 | |
772 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-28)), | |
773 | BOOST_MATH_TEST_VALUE(RealType, -68.702163291525429160769761667024460023336801014578), | |
774 | tolerance); | |
775 | ||
776 | // Check for overflow when using a double (including when using for approximate value for refinement for higher precision). | |
777 | ||
778 | // N[productlog(-1, -10 ^ -30), 50] = -73.373110313822976797067478758120874529181611813766 | |
779 | //BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e30)), | |
780 | // BOOST_MATH_TEST_VALUE(RealType, -73.373110313822976797067478758120874529181611813766), | |
781 | // tolerance); | |
782 | //unknown location : fatal error : in "test_types" : | |
783 | //class boost::exception_detail::clone_impl<struct boost::exception_detail::error_info_injector<class std::domain_error> > | |
784 | // : Error in function boost::math::lambert_wm1<RealType>(<RealType>) : | |
785 | // Argument z = -1.00000002e+30 out of range(z < -exp(-1) = -3.6787944) for Lambert W - 1 branch! | |
786 | ||
787 | BOOST_CHECK_THROW(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e30)), std::domain_error); | |
788 | ||
789 | // Too negative | |
790 | BOOST_CHECK_THROW(lambert_wm1(RealType(-0.5)), std::domain_error); | |
791 | ||
792 | // This fails for fixed_point type used for other tests because out of range? | |
793 | //BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.0e6)), | |
794 | //BOOST_MATH_TEST_VALUE(RealType, 11.383358086140052622000156781585004289033774706019), | |
795 | //// Output from https://www.wolframalpha.com/input/?i=lambert_w0(1e6) | |
796 | //// tolerance * 1000); // fails for fixed_point type exceeds 0.00015258789063 | |
797 | // // 15.258789063 | |
798 | // // 11.383346558 | |
799 | // tolerance * 100000); | |
800 | // So need to use some spot tests for specific types, or use a bigger fixed_point type. | |
801 | ||
802 | // Check zero. | |
803 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.0)), | |
804 | BOOST_MATH_TEST_VALUE(RealType, 0.0), | |
805 | tolerance); | |
806 | // these fail for cpp_dec_float_50 | |
807 | // 'boost::multiprecision::detail::expression<boost::multiprecision::detail::negate,boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<50,int32_t,void>,boost::multiprecision::et_on>,void,void,void>' | |
808 | // : no appropriate default constructor available | |
809 | // TODO ??????????? | |
810 | ||
811 | } // template <class RealType>void test_spots(RealType) | |
812 | ||
813 | BOOST_AUTO_TEST_CASE( test_types ) | |
814 | { | |
815 | BOOST_MATH_CONTROL_FP; | |
816 | // BOOST_TEST_MESSAGE output only appears if command line has --log_level="message" | |
817 | // or call set_threshold_level function: | |
f67539c2 TL |
818 | // boost::unit_test::unit_test_log.set_threshold_level(boost::unit_test_framework::log_messages); |
819 | ||
820 | BOOST_TEST_MESSAGE("\nTest Lambert W function for several types.\n"); | |
92f5a8d4 TL |
821 | BOOST_TEST_MESSAGE(show_versions()); // Full version of Boost, STL and compiler info. |
822 | #ifndef BOOST_MATH_TEST_MULTIPRECISION | |
823 | // Fundamental built-in types: | |
824 | test_spots(0.0F); // float | |
825 | test_spots(0.0); // double | |
826 | #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS | |
827 | if (sizeof(long double) > sizeof(double)) | |
828 | { // Avoid pointless re-testing if double and long double are identical (for example, MSVC). | |
829 | test_spots(0.0L); // long double | |
830 | } | |
1e59de90 | 831 | #ifndef BOOST_MATH_NO_REAL_CONCEPT_TESTS |
92f5a8d4 | 832 | test_spots(boost::math::concepts::real_concept(0)); |
1e59de90 | 833 | #endif |
92f5a8d4 TL |
834 | #endif |
835 | ||
836 | #else // BOOST_MATH_TEST_MULTIPRECISION | |
837 | // Multiprecision types: | |
1e59de90 TL |
838 | #if BOOST_MATH_TEST_MULTIPRECISION == 1 && !defined(BOOST_MATH_NO_REAL_CONCEPT_TESTS) |
839 | #if (LDBL_MANT_DIG <= 64) // Otherwise we get inscrutable errors from multiprecision, which may or may not be a bug... | |
92f5a8d4 TL |
840 | test_spots(static_cast<boost::multiprecision::cpp_bin_float_double_extended>(0)); |
841 | #endif | |
1e59de90 TL |
842 | #endif |
843 | #if BOOST_MATH_TEST_MULTIPRECISION == 2 && !defined(BOOST_MATH_NO_REAL_CONCEPT_TESTS) | |
92f5a8d4 TL |
844 | test_spots(static_cast<boost::multiprecision::cpp_bin_float_quad>(0)); |
845 | #endif | |
1e59de90 | 846 | #if BOOST_MATH_TEST_MULTIPRECISION == 3 && !defined(BOOST_MATH_NO_REAL_CONCEPT_TESTS) |
92f5a8d4 TL |
847 | test_spots(static_cast<boost::multiprecision::cpp_bin_float_50>(0)); |
848 | #endif | |
849 | #endif // ifdef BOOST_MATH_TEST_MULTIPRECISION | |
850 | ||
851 | #ifdef BOOST_MATH_TEST_FLOAT128 | |
852 | std::cout << "\nBOOST_MATH_TEST_FLOAT128 defined for float128 tests." << std::endl; | |
853 | ||
854 | #ifdef BOOST_HAS_FLOAT128 | |
855 | // GCC and Intel only. | |
856 | // Requires link to libquadmath library, see | |
857 | // http://www.boost.org/doc/libs/release/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/float128.html | |
858 | // for example: | |
859 | // C:\Program Files\mingw-w64\x86_64-7.2.0-win32-seh-rt_v5-rev1\mingw64\lib\gcc\x86_64-w64-mingw32\7.2.0\libquadmath.a | |
860 | ||
861 | using boost::multiprecision::float128; | |
862 | std::cout << "BOOST_HAS_FLOAT128" << std::endl; | |
863 | ||
864 | std::cout.precision(std::numeric_limits<float128>::max_digits10); | |
865 | ||
866 | test_spots(static_cast<float128>(0)); | |
867 | #endif // BOOST_HAS_FLOAT128 | |
868 | #else | |
869 | std::cout << "\nBOOST_MATH_TEST_FLOAT128 NOT defined so NO float128 tests." << std::endl; | |
870 | #endif // #ifdef BOOST_MATH_TEST_FLOAT128 | |
871 | ||
872 | } // BOOST_AUTO_TEST_CASE( test_types ) | |
873 | ||
874 | ||
875 | BOOST_AUTO_TEST_CASE( test_range_of_double_values ) | |
876 | { | |
877 | using boost::math::constants::exp_minus_one; | |
878 | using boost::math::lambert_w0; | |
879 | ||
880 | BOOST_TEST_MESSAGE("\nTest Lambert W function type double for range of values."); | |
881 | ||
882 | // Want to test almost largest value. | |
883 | // test_value = (std::numeric_limits<RealType>::max)() / 4; | |
884 | // std::cout << std::setprecision(std::numeric_limits<RealType>::max_digits10) << "Max value = " << test_value << std::endl; | |
885 | // Can't use a test like this for all types because max_value depends on RealType | |
886 | // and thus the expected result of lambert_w0 does too. | |
887 | //BOOST_CHECK_CLOSE_FRACTION(lambert_w0<RealType>(test_value), | |
888 | // BOOST_MATH_TEST_VALUE(RealType, ???), | |
889 | // tolerance); | |
890 | // So this section just tests a single type, say IEEE 64-bit double, for a range of spot values. | |
891 | ||
892 | typedef double RealType; // Some tests assume type is double. | |
893 | ||
894 | int epsilons = 1; | |
895 | RealType tolerance = boost::math::tools::epsilon<RealType>() * epsilons; // 2 eps as a fraction. | |
896 | std::cout << "Tolerance " << epsilons << " * epsilon == " << tolerance << std::endl; | |
897 | ||
898 | #ifndef BOOST_MATH_TEST_MULTIPRECISION | |
899 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.0e-6)), | |
900 | BOOST_MATH_TEST_VALUE(RealType, 9.9999900000149999733333854165586669000967020964243e-7), | |
901 | // Output from https://www.wolframalpha.com/input/ N[lambert_w[1e-6],50]) | |
902 | tolerance); | |
903 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.0001)), | |
904 | BOOST_MATH_TEST_VALUE(RealType, 0.000099990001499733385405869000452213835767629477903460), | |
905 | // Output from https://www.wolframalpha.com/input/ N[lambert_w[0.001],50]) | |
906 | tolerance); | |
907 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.001)), | |
908 | BOOST_MATH_TEST_VALUE(RealType, 0.00099900149733853088995782787410778559957065467928884), | |
909 | // Output from https://www.wolframalpha.com/input/ N[lambert_w[0.001],50]) | |
910 | tolerance); | |
911 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.01)), | |
912 | BOOST_MATH_TEST_VALUE(RealType, 0.0099014738435950118853363268165701079536277464949174), | |
913 | // Output from https://www.wolframalpha.com/input/ N[lambert_w[0.01],50]) | |
914 | tolerance * 25); // <<< Needs a much bigger tolerance??? | |
915 | // 0.0099014738435951096 this test max_digits10 | |
916 | // 0.00990147384359511 digits10 | |
917 | // 0.0099014738435950118 wolfram | |
918 | // 0.00990147384359501 wolfram digits10 | |
919 | // 0.0099014738435950119 N[lambert_w[0.01],17] | |
920 | // 0.00990147384359501 N[lambert_w[0.01],15] which really is more different than expected. | |
921 | // 0.00990728209160670 approx | |
922 | // 0.00990147384359511 previous | |
923 | ||
924 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.05)), | |
925 | BOOST_MATH_TEST_VALUE(RealType, 0.047672308600129374726388900514160870747062965933891), | |
926 | // Output from https://www.wolframalpha.com/input/ N[lambert_w[0.01],50]) | |
927 | tolerance); | |
928 | ||
929 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.1)), | |
930 | BOOST_MATH_TEST_VALUE(RealType, 0.091276527160862264299895721423179568653119224051472), | |
931 | // Output from https://www.wolframalpha.com/input/ N[lambert_w[1],50]) | |
932 | tolerance); | |
933 | ||
934 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.)), | |
935 | BOOST_MATH_TEST_VALUE(RealType, 0.56714329040978387299996866221035554975381578718651), | |
936 | // Output from https://www.wolframalpha.com/input/ N[lambert_w[1],50]) | |
937 | tolerance); | |
938 | ||
939 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 2.)), | |
940 | BOOST_MATH_TEST_VALUE(RealType, 0.852605502013725491346472414695317466898453300151403508772), | |
941 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(2.) | |
942 | tolerance); | |
943 | ||
944 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 3.)), | |
945 | BOOST_MATH_TEST_VALUE(RealType, 1.049908894964039959988697070552897904589466943706341452932), | |
946 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(3.) | |
947 | tolerance); | |
948 | ||
949 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 5.)), | |
950 | BOOST_MATH_TEST_VALUE(RealType, 1.326724665242200223635099297758079660128793554638047479789), | |
951 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(0.5) | |
952 | tolerance); | |
953 | ||
954 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 6.)), | |
955 | BOOST_MATH_TEST_VALUE(RealType, 1.432404775898300311234078007212058694786434608804302025655), | |
956 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(6) | |
957 | tolerance); | |
958 | ||
959 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 10.)), | |
960 | BOOST_MATH_TEST_VALUE(RealType, 1.7455280027406993830743012648753899115352881290809), | |
961 | // Output from https://www.wolframalpha.com/input/ N[lambert_w[10],50]) | |
962 | tolerance); | |
963 | ||
964 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 100.)), | |
965 | BOOST_MATH_TEST_VALUE(RealType, 3.3856301402900501848882443645297268674916941701578), | |
966 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(100) | |
967 | tolerance); | |
968 | ||
969 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1000.)), | |
970 | BOOST_MATH_TEST_VALUE(RealType, 5.2496028524015962271260563196973062825214723860596), | |
971 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(1000) | |
972 | tolerance); | |
973 | ||
974 | // This fails for fixed_point type used for other tests because out of range of the type? | |
975 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.0e6)), | |
976 | BOOST_MATH_TEST_VALUE(RealType, 11.383358086140052622000156781585004289033774706019), | |
977 | // Output from https://www.wolframalpha.com/input/?i=lambert_w0(1e6) | |
978 | tolerance); // | |
979 | ||
980 | // Tests for double only near the max and the singularity where Lambert_w estimates are less precise. | |
981 | if (std::numeric_limits<RealType>::is_specialized) | |
982 | { // is_specialized means that can use numeric_limits for tests. | |
983 | // Check near std::numeric_limits<>::max() for type. | |
984 | //std::cout << std::setprecision(std::numeric_limits<RealType>::max_digits10) | |
985 | // << (std::numeric_limits<double>::max)() // == 1.7976931348623157e+308 | |
986 | // << " " << (std::numeric_limits<double>::max)()/4 // == 4.4942328371557893e+307 | |
987 | // << std::endl; | |
988 | ||
989 | // All these result in faulty error message | |
990 | // unknown location : fatal error : in "test_range_of_values": class boost::exception_detail::clone_impl<struct boost::exception_detail::error_info_injector<class std::domain_error> >: Error in function boost::math::lambert_w0<RealType>(<RealType>): Argument z = %1 too large. | |
991 | // I:\modular - boost\libs\math\test\test_lambert_w.cpp(456) : last checkpoint | |
992 | ||
993 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(1.7976931348623157e+308 ), // max_value for IEEE 64-bit double. | |
994 | static_cast<double>(703.2270331047701868711791887193075929608934699575820028L), | |
995 | // N[productlog[0, 1.7976931348623157*10^308 /2],50] == 702.53487067487671916110655783739076368512998658347 | |
996 | tolerance); | |
997 | ||
998 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(1.7976931348623157e+308 / 2), // max_value/2 for IEEE 64-bit double. | |
999 | static_cast<double>(702.53487067487671916110655783739076368512998658347L), | |
1000 | // N[productlog[0, 1.7976931348623157*10^308 /2],50] == 702.53487067487671916110655783739076368512998658347 | |
1001 | tolerance); | |
1002 | ||
1003 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(1.7976931348623157e+308 /4), // near max_value/4 for IEEE 64-bit double. | |
1004 | static_cast<double>(701.8427092142920014223182853764045476L), | |
1005 | // N[productlog(0, 1.7976931348623157* 10^308 /4 ), 37] =701.8427092142920014223182853764045476 | |
1006 | // N[productlog(0, 0.25 * 1.7976931348623157*10^307), 37] | |
1007 | tolerance); | |
1008 | ||
1009 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(4.4942328371557893e+307), // max_value/4 for IEEE 64-bit double. | |
1010 | static_cast<double>(701.84270921429200143342782556643059L), | |
1011 | // N[lambert_w[4.4942328371557893e+307], 35] == 701.8427092142920014334278255664305887 | |
1012 | // as a double == 701.83341468208209 | |
1013 | // Lambert computed 702.02379914670587 | |
1014 | 0.000003); // OK Much less precise at the max edge??? | |
1015 | ||
1016 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0((std::numeric_limits<double>::max)()), // max_value for IEEE 64-bit double. | |
1017 | static_cast<double>(703.2270331047701868711791887193075930), | |
1018 | // N[productlog(0, 1.7976931348623157* 10^308), 37] = 703.2270331047701868711791887193075930 | |
1019 | // 703.22700325995515 lambert W | |
1020 | // 703.22703310477016 Wolfram | |
1021 | tolerance * 2e8); // OK but much less accurate near max. | |
1022 | ||
1023 | // Compare precisions very close to the singularity. | |
1024 | // This test value is one epsilon close to the singularity at -exp(-1) * z | |
1025 | // (below which the result has a non-zero imaginary part). | |
1026 | RealType test_value = -exp_minus_one<RealType>(); | |
1027 | test_value += (std::numeric_limits<RealType>::epsilon() * 1); | |
1028 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(test_value), | |
1029 | BOOST_MATH_TEST_VALUE(RealType, -0.99999996349975895), | |
1030 | tolerance * 1000000000); | |
1031 | // -0.99999996788201051 | |
1032 | // -0.99999996349975895 | |
1033 | // Would not expect to get a result closer than sqrt(epsilon)? | |
1034 | } // if (std::numeric_limits<RealType>::is_specialized) | |
1035 | ||
1036 | // Can only compare float_next for specific type T = double. | |
1037 | // Comparison with Wolfram N[productlog(0,-0.36787944117144228 ), 17] | |
1038 | // Note big loss of precision and big tolerance needed to pass. | |
1039 | BOOST_CHECK_CLOSE_FRACTION( // Check float_next(-exp(-1) ) | |
1040 | lambert_w0(BOOST_MATH_TEST_VALUE(double, -0.36787944117144228)), | |
1041 | BOOST_MATH_TEST_VALUE(RealType, -0.99999998496215738), | |
1042 | 1e8 * tolerance); // diff 6.03558e-09 v 2.2204460492503131e-16 | |
1043 | ||
1044 | BOOST_CHECK_CLOSE_FRACTION( // Check float_next(float_next(-exp(-1) )) | |
1045 | lambert_w0(BOOST_MATH_TEST_VALUE(double, -0.36787944117144222)), | |
1046 | BOOST_MATH_TEST_VALUE(RealType, -0.99999997649828679), | |
1047 | 5e7 * tolerance);// diff 2.30785e-09 v 2.2204460492503131e-16 | |
1048 | ||
f67539c2 TL |
1049 | // Compare with previous PB/FK computations at double precision. |
1050 | using std::abs; | |
1051 | RealType x = BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144228); | |
1052 | RealType w0 = lambert_w0(x); | |
1053 | RealType w0_prime = boost::math::lambert_w0_prime(x); | |
1054 | RealType mu = std::numeric_limits<RealType>::epsilon()/2; | |
1055 | BOOST_CHECK_CLOSE_FRACTION( // Check float_next(-exp(-1) ) | |
1056 | w0, | |
1057 | BOOST_MATH_TEST_VALUE(RealType, -0.9999999849621573837115797120602890516186071783122773515945338502828025975466699519609633476854139977), | |
1058 | 2*mu*abs(x*w0_prime/w0)); // diff 6.03558e-09 v 2.2204460492503131e-16 | |
1059 | ||
1060 | x = BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144222); | |
1061 | w0 = lambert_w0(x); | |
1062 | w0_prime = boost::math::lambert_w0_prime(x); | |
1063 | BOOST_CHECK_CLOSE_FRACTION( // Check float_next(float_next(-exp(-1) )) | |
1064 | w0, | |
92f5a8d4 | 1065 | BOOST_MATH_TEST_VALUE(RealType, -0.99999997419043196), |
f67539c2 | 1066 | 2*mu*abs(x*w0_prime/w0));// diff 2.30785e-09 v 2.2204460492503131e-16 |
92f5a8d4 TL |
1067 | |
1068 | // z increasingly close to singularity. | |
1069 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.36)), | |
1070 | BOOST_MATH_TEST_VALUE(RealType, -0.8060843159708177782855213616209920019974599683466713016), | |
1071 | 2 * tolerance); // -0.806084335 | |
1072 | ||
1073 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.365)), | |
1074 | BOOST_MATH_TEST_VALUE(RealType, -0.8798200914159538111724840007674053239388642469453350954), | |
1075 | 5 * tolerance); // Note 5 * tolerance | |
1076 | ||
1077 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.3678)), | |
1078 | BOOST_MATH_TEST_VALUE(RealType, -0.9793607149578284774761844434886481686055949229547379368), | |
1079 | 15 * tolerance); // Note 15 * tolerance when this close to singularity. | |
1080 | ||
1081 | // Just using series approximation (Fukushima switch at -0.35, but JM at 0.01 of singularity < -0.3679). | |
1082 | // N[productlog(-0.351), 50] = -0.72398644140937651483634596143951001600417138085814 | |
1083 | // N[productlog(-0.351), 55] = -0.7239864414093765148363459614395100160041713808581379727 | |
1084 | BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.351)), | |
1085 | BOOST_MATH_TEST_VALUE(RealType, -0.72398644140937651483634596143951001600417138085814), | |
1086 | 10 * tolerance); // Note was 2 * tolerance | |
1087 | ||
1088 | // Check value just not using near_singularity series approximation (and using rational polynomial instead). | |
1089 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.3)), | |
1090 | BOOST_MATH_TEST_VALUE(RealType, -1.7813370234216276119741702815127452608215583564545), | |
1091 | // Output from https://www.wolframalpha.com/input/ | |
1092 | //N[productlog(-1, -0.3), 50] = -1.7813370234216276119741702815127452608215583564545 | |
1093 | tolerance); | |
1094 | ||
1095 | // Using table lookup and schroeder with decreasing z to zero. | |
1096 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.2)), | |
1097 | BOOST_MATH_TEST_VALUE(RealType, -2.5426413577735264242938061566618482901614749075294), | |
1098 | // N[productlog[-1, -0.2],50] -2.5426413577735264242938061566618482901614749075294 | |
1099 | tolerance); | |
1100 | ||
1101 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.1)), | |
1102 | BOOST_MATH_TEST_VALUE(RealType, -3.5771520639572972184093919635119948804017962577931), | |
1103 | //N[productlog(-1, -0.1), 50] = -3.5771520639572972184093919635119948804017962577931 | |
1104 | tolerance); | |
1105 | ||
1106 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.001)), | |
1107 | BOOST_MATH_TEST_VALUE(RealType, -9.1180064704027401212583371820468142742704349737639), | |
1108 | // N[productlog(-1, -0.001), 50] = -9.1180064704027401212583371820468142742704349737639 | |
1109 | tolerance); | |
1110 | ||
1111 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.000001)), | |
1112 | BOOST_MATH_TEST_VALUE(RealType, -16.626508901372473387706432163984684996461726803805), | |
1113 | // N[productlog(-1, -0.000001), 50] = -16.626508901372473387706432163984684996461726803805 | |
1114 | tolerance); | |
1115 | ||
1116 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-6)), | |
1117 | BOOST_MATH_TEST_VALUE(RealType, -16.626508901372473387706432163984684996461726803805), | |
1118 | // N[productlog(-1, -10 ^ -6), 50] = -16.626508901372473387706432163984684996461726803805 | |
1119 | tolerance); | |
1120 | ||
1121 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1.0e-26)), | |
1122 | BOOST_MATH_TEST_VALUE(RealType, -64.026509628385889681156090340691637712441162092868), | |
1123 | // Output from https://www.wolframalpha.com/input/ | |
1124 | // N[productlog(-1, -1 * 10^-26 ), 50] = -64.026509628385889681156090340691637712441162092868 | |
1125 | tolerance); | |
1126 | ||
1127 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -2e-26)), | |
1128 | BOOST_MATH_TEST_VALUE(RealType, -63.322302839923597803393585145387854867226970485197), | |
1129 | // N[productlog[-1, -2*10^-26],50] = -63.322302839923597803393585145387854867226970485197 | |
1130 | tolerance * 2); | |
1131 | ||
1132 | // Smaller than lookup table, so must use approx and Halley refinements. | |
1133 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-30)), | |
1134 | BOOST_MATH_TEST_VALUE(RealType, -73.373110313822976797067478758120874529181611813766), | |
1135 | // N[productlog(-1, -10 ^ -30), 50] = -73.373110313822976797067478758120874529181611813766 | |
1136 | tolerance); | |
1137 | ||
1138 | // std::numeric_limits<RealType>::min | |
1139 | #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS | |
1140 | std::cout.precision(std::numeric_limits<RealType>::max_digits10); | |
1141 | #endif | |
1142 | std::cout << "(std::numeric_limits<RealType>::min)() " << (std::numeric_limits<RealType>::min)() << std::endl; | |
1143 | ||
1144 | BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -2.2250738585072014e-308)), | |
1145 | BOOST_MATH_TEST_VALUE(RealType, -714.96865723796647086868547560654825435542227693935), | |
1146 | // N[productlog[-1, -2.2250738585072014e-308],50] = -714.96865723796647086868547560654825435542227693935 | |
1147 | tolerance); | |
1148 | ||
1149 | // For z = 0, W = -infinity | |
1150 | if (std::numeric_limits<RealType>::has_infinity) | |
1151 | { | |
1152 | BOOST_CHECK_EQUAL(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, 0.)), | |
1153 | -std::numeric_limits<RealType>::infinity()); | |
1154 | } | |
1155 | ||
1156 | #elif BOOST_MATH_TEST_MULTIPRECISION == 2 | |
1157 | ||
1158 | // Comparison with Wolfram N[productlog(0,-0.36787944117144228 ), 17] | |
1159 | // Using conversion from double to higher precision cpp_bin_float_quad | |
1160 | using boost::multiprecision::cpp_bin_float_quad; | |
1161 | BOOST_CHECK_CLOSE_FRACTION( // Check float_next(-exp(-1) ) | |
1162 | lambert_w0(BOOST_MATH_TEST_VALUE(cpp_bin_float_quad, -0.36787944117144228)), | |
1163 | BOOST_MATH_TEST_VALUE(cpp_bin_float_quad, -0.99999998496215738), | |
1164 | tolerance); // OK | |
1165 | ||
1166 | BOOST_CHECK_CLOSE_FRACTION( // Check float_next(float_next(-exp(-1) )) | |
1167 | lambert_w0(BOOST_MATH_TEST_VALUE(cpp_bin_float_quad, -0.36787944117144222)), | |
1168 | BOOST_MATH_TEST_VALUE(cpp_bin_float_quad, -0.99999997649828679), | |
1169 | tolerance);// OK | |
1170 | #endif | |
1171 | } // BOOST_AUTO_TEST_CASE(test_range_of_double_values) | |
1172 |