test_lambert_w.cpp 85 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145
  1. // Copyright Paul A. Bristow 2016, 2017, 2018.
  2. // Copyright John Maddock 2016.
  3. // Use, modification and distribution are subject to the
  4. // Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt
  6. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. // test_lambert_w.cpp
  8. //! \brief Basic sanity tests for Lambert W function using algorithms
  9. // informed by Thomas Luu, Darko Veberic and Tosio Fukushima for W0
  10. // and rational polynomials by John Maddock.
  11. // #define BOOST_MATH_TEST_MULTIPRECISION // Add tests for several multiprecision types (not just built-in).
  12. // #define BOOST_MATH_TEST_FLOAT128 // Add test using float128 type (GCC only, needing gnu++17 and quadmath library).
  13. #ifdef BOOST_MATH_TEST_FLOAT128
  14. #include <boost/cstdfloat.hpp> // For float_64_t, float128_t. Must be first include!
  15. #endif // #ifdef #ifdef BOOST_MATH_TEST_FLOAT128
  16. // Needs gnu++17 for BOOST_HAS_FLOAT128
  17. #include <boost/config.hpp> // for BOOST_MSVC definition etc.
  18. #include <boost/version.hpp> // for BOOST_MSVC versions.
  19. // Boost macros
  20. #define BOOST_TEST_MAIN
  21. #define BOOST_LIB_DIAGNOSTIC "on" // Report library file details.
  22. #include <boost/test/included/unit_test.hpp> // Boost.Test
  23. // #include <boost/test/unit_test.hpp> // Boost.Test
  24. #include <boost/test/tools/floating_point_comparison.hpp>
  25. #include <boost/array.hpp>
  26. #include <boost/lexical_cast.hpp>
  27. #include <boost/type_traits/is_constructible.hpp>
  28. #ifdef BOOST_MATH_TEST_MULTIPRECISION
  29. #include <boost/multiprecision/cpp_dec_float.hpp> // boost::multiprecision::cpp_dec_float_50
  30. using boost::multiprecision::cpp_dec_float_50;
  31. #include <boost/multiprecision/cpp_bin_float.hpp>
  32. using boost::multiprecision::cpp_bin_float_quad;
  33. #include <boost/math/concepts/real_concept.hpp>
  34. #ifdef BOOST_MATH_TEST_FLOAT128
  35. #ifdef BOOST_HAS_FLOAT128
  36. // Including this header below without float128 triggers:
  37. // fatal error C1189: #error: "Sorry compiler is neither GCC, not Intel, don't know how to configure this header."
  38. #include <boost/multiprecision/float128.hpp>
  39. using boost::multiprecision::float128;
  40. #endif // ifdef BOOST_HAS_FLOAT128
  41. #endif // #ifdef #ifdef BOOST_MATH_TEST_FLOAT128
  42. #endif // #ifdef BOOST_MATH_TEST_MULTIPRECISION
  43. //#include <boost/fixed_point/fixed_point.hpp> // If available.
  44. #include <boost/math/concepts/real_concept.hpp> // for real_concept tests.
  45. #include <boost/math/special_functions/fpclassify.hpp> // isnan, ifinite.
  46. #include <boost/math/special_functions/next.hpp> // float_next, float_prior
  47. using boost::math::float_next;
  48. using boost::math::float_prior;
  49. #include <boost/math/special_functions/ulp.hpp> // ulp
  50. #include <boost/math/tools/test_value.hpp> // for create_test_value and macro BOOST_MATH_TEST_VALUE.
  51. #include <boost/math/policies/policy.hpp>
  52. using boost::math::policies::digits2;
  53. using boost::math::policies::digits10;
  54. #include <boost/math/special_functions/lambert_w.hpp> // For Lambert W lambert_w function.
  55. using boost::math::lambert_wm1;
  56. using boost::math::lambert_w0;
  57. #include "table_type.hpp"
  58. #ifndef SC_
  59. # define SC_(x) boost::lexical_cast<typename table_type<T>::type>(BOOST_STRINGIZE(x))
  60. #endif
  61. #include <limits>
  62. #include <cmath>
  63. #include <typeinfo>
  64. #include <iostream>
  65. #include <exception>
  66. std::string show_versions(void);
  67. //! Build a message of information about build, architecture, address model, platform, ...
  68. std::string show_versions(void)
  69. {
  70. // Some of this information can also be obtained from running with a Custom Post-build step
  71. // adding the option --build_info=yes
  72. // "$(TargetDir)$(TargetName).exe" --build_info=yes
  73. std::ostringstream message;
  74. message << "Program: " << __FILE__ << "\n";
  75. #ifdef __TIMESTAMP__
  76. message << __TIMESTAMP__;
  77. #endif
  78. message << "\nBuildInfo:\n" " Platform " << BOOST_PLATFORM;
  79. // http://stackoverflow.com/questions/1505582/determining-32-vs-64-bit-in-c
  80. #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
  81. message << ", 64-bit.";
  82. #else
  83. message << ", 32-bit.";
  84. #endif
  85. message << "\n Compiler " BOOST_COMPILER;
  86. #ifdef BOOST_MSC_VER
  87. #ifdef _MSC_FULL_VER
  88. message << "\n MSVC version " << BOOST_STRINGIZE(_MSC_FULL_VER) << ".";
  89. #endif
  90. #ifdef __WIN64
  91. mess age << "\n WIN64" << std::endl;
  92. #endif // __WIN64
  93. #ifdef _WIN32
  94. message << "\n WIN32" << std::endl;
  95. #endif // __WIN32
  96. #endif
  97. #ifdef __GNUC__
  98. //PRINT_MACRO(__GNUC__);
  99. //PRINT_MACRO(__GNUC_MINOR__);
  100. //PRINT_MACRO(__GNUC_PATCH__);
  101. std::cout << "GCC " << __VERSION__ << std::endl;
  102. //PRINT_MACRO(LONG_MAX);
  103. #endif // __GNUC__
  104. #ifdef __MINGW64__
  105. std::cout << "MINGW64 " << __MINGW32_MAJOR_VERSION << __MINGW32_MINOR_VERSION << std::endl;
  106. //
  107. // << __MINGW64_MAJOR_VERSION << __MINGW64_MINOR_VERSION << std::endl; not declared in this scope???
  108. #endif // __MINGW64__
  109. #ifdef __MINGW32__
  110. std::cout << "MINGW64 " << __MINGW32_MAJOR_VERSION << __MINGW32_MINOR_VERSION << std::endl;
  111. #endif // __MINGW32__
  112. message << "\n STL " << BOOST_STDLIB;
  113. message << "\n Boost version " << BOOST_VERSION / 100000 << "." << BOOST_VERSION / 100 % 1000 << "." << BOOST_VERSION % 100;
  114. #ifdef BOOST_MATH_TEST_MULTIPRECISION
  115. message << "\nBOOST_MATH_TEST_MULTIPRECISION defined for multiprecision tests. " << std::endl;
  116. #else
  117. message << "\nBOOST_MATH_TEST_MULTIPRECISION not defined so NO multiprecision tests. " << std::endl;
  118. #endif // BOOST_MATH_TEST_MULTIPRECISION
  119. #ifdef BOOST_HAS_FLOAT128
  120. message << "BOOST_HAS_FLOAT128 is defined." << std::endl;
  121. #endif // ifdef BOOST_HAS_FLOAT128
  122. message << std::endl;
  123. return message.str();
  124. } // std::string show_versions()
  125. template <class T>
  126. void wolfram_test_moderate_values()
  127. {
  128. //
  129. // 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
  130. //
  131. static const boost::array<boost::array<typename table_type<T>::type, 2>, 96/2> wolfram_test_small_neg =
  132. {{
  133. {{ 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) }}
  134. }};
  135. T tolerance = boost::math::tools::epsilon<T>() * 3;
  136. if (std::numeric_limits<T>::digits10 > 40)
  137. tolerance *= 4; // arbitrary precision types have lower accuracy on exp(z).
  138. for (unsigned i = 0; i < wolfram_test_small_neg.size(); ++i)
  139. {
  140. BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(T(wolfram_test_small_neg[i][0])), T(wolfram_test_small_neg[i][1]), tolerance);
  141. }
  142. }
  143. template <class T>
  144. void wolfram_test_small_pos()
  145. {
  146. //
  147. // 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
  148. //
  149. static const boost::array<boost::array<typename table_type<T>::type, 2>, 25> wolfram_test_small_neg =
  150. {{
  151. {{ 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) }}
  152. }};
  153. T tolerance = boost::math::tools::epsilon<T>() * 3;
  154. if (std::numeric_limits<T>::digits10 > 40)
  155. tolerance *= 3; // arbitrary precision types have lower accuracy on exp(z).
  156. for (unsigned i = 0; i < wolfram_test_small_neg.size(); ++i)
  157. {
  158. BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(T(wolfram_test_small_neg[i][0])), T(wolfram_test_small_neg[i][1]), tolerance);
  159. }
  160. }
  161. template <class T>
  162. void wolfram_test_small_neg()
  163. {
  164. //
  165. // 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
  166. //
  167. static const boost::array<boost::array<typename table_type<T>::type, 2>, 70/2> wolfram_test_small_neg =
  168. {{
  169. {{ 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) }},
  170. {{ 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) }}
  171. }};
  172. T tolerance = boost::math::tools::epsilon<T>() * 3;
  173. if (std::numeric_limits<T>::digits10 > 40)
  174. tolerance *= 3; // arbitrary precision types have lower accuracy on exp(z).
  175. for (unsigned i = 0; i < wolfram_test_small_neg.size(); ++i)
  176. {
  177. BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(T(wolfram_test_small_neg[i][0])), T(wolfram_test_small_neg[i][1]), tolerance);
  178. }
  179. }
  180. template <class T>
  181. void wolfram_test_large(const boost::mpl::true_&)
  182. {
  183. //
  184. // 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
  185. //
  186. static const boost::array<boost::array<typename table_type<T>::type, 2>, 28/2> wolfram_test_large_data =
  187. { {
  188. {{ 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) }}
  189. } };
  190. T tolerance = boost::math::tools::epsilon<T>() * 3;
  191. if (std::numeric_limits<T>::digits10 > 40)
  192. tolerance *= 3; // arbitrary precision types have lower accuracy on exp(z).
  193. for (unsigned i = 0; i < wolfram_test_large_data.size(); ++i)
  194. {
  195. BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(T(wolfram_test_large_data[i][0])), T(wolfram_test_large_data[i][1]), tolerance);
  196. }
  197. }
  198. template <class T>
  199. void wolfram_test_large(const boost::mpl::false_&){}
  200. template <class T>
  201. void wolfram_test_large()
  202. {
  203. wolfram_test_large<T>(boost::mpl::bool_<(std::numeric_limits<T>::max_exponent10 > 1000)>());
  204. }
  205. template <class T>
  206. void wolfram_test_near_singularity()
  207. {
  208. //
  209. // 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
  210. //
  211. static const boost::array<boost::array<typename table_type<T>::type, 2>, 39> wolfram_test_near_singularity_data =
  212. {{
  213. { { 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) } }
  214. }};
  215. T tolerance = boost::math::tools::epsilon<T>() * 3;
  216. if (boost::math::tools::epsilon<T>() <= boost::math::tools::epsilon<long double>())
  217. tolerance *= 5e5;
  218. T endpoint = -boost::math::constants::exp_minus_one<T>();
  219. for (unsigned i = 0; i < wolfram_test_near_singularity_data.size(); ++i)
  220. {
  221. if (wolfram_test_near_singularity_data[i][0] <= endpoint)
  222. break;
  223. else
  224. 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);
  225. }
  226. }
  227. template <>
  228. void wolfram_test_near_singularity<float>()
  229. {
  230. //
  231. // Spot values near the singularity with inputs truncated to float precision,
  232. // 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
  233. //
  234. static const boost::array<boost::array<float, 2>, 39> wolfram_test_near_singularity_data =
  235. {{
  236. {{ -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 }}
  237. }};
  238. float tolerance = boost::math::tools::epsilon<float>() * 16;
  239. float endpoint = -boost::math::constants::exp_minus_one<float>();
  240. for (unsigned i = 0; i < wolfram_test_near_singularity_data.size(); ++i)
  241. {
  242. if (wolfram_test_near_singularity_data[i][0] <= endpoint)
  243. break;
  244. else
  245. BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(wolfram_test_near_singularity_data[i][0]), wolfram_test_near_singularity_data[i][1], tolerance);
  246. }
  247. }
  248. template <>
  249. void wolfram_test_near_singularity<double>()
  250. {
  251. //
  252. // Spot values near the singularity with inputs truncated to double precision,
  253. // 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
  254. //
  255. static const boost::array<boost::array<double, 2>, 39> wolfram_test_near_singularity_data =
  256. {{
  257. {{ -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 }}
  258. }};
  259. double tolerance = boost::math::tools::epsilon<double>() * 5;
  260. if (std::numeric_limits<double>::digits >= std::numeric_limits<long double>::digits)
  261. tolerance *= 1e5;
  262. else if (std::numeric_limits<double>::digits * 2 >= std::numeric_limits<long double>::digits)
  263. tolerance *= 5e4;
  264. double endpoint = -boost::math::constants::exp_minus_one<double>();
  265. for (unsigned i = 0; i < wolfram_test_near_singularity_data.size(); ++i)
  266. {
  267. if (wolfram_test_near_singularity_data[i][0] <= endpoint)
  268. break;
  269. else
  270. BOOST_CHECK_CLOSE_FRACTION(boost::math::lambert_w0(wolfram_test_near_singularity_data[i][0]), wolfram_test_near_singularity_data[i][1], tolerance);
  271. }
  272. }
  273. template <class RealType>
  274. void test_spots(RealType)
  275. {
  276. // (Unused Parameter value, arbitrarily zero, only communicates the floating point type).
  277. // test_spots(0.F); test_spots(0.); test_spots(0.L);
  278. using boost::math::lambert_w0;
  279. using boost::math::lambert_wm1;
  280. using boost::math::constants::exp_minus_one;
  281. using boost::math::constants::e;
  282. using boost::math::policies::policy;
  283. /* Example of an exception-free 'ignore_all' policy (possibly ill-advised?).
  284. */
  285. typedef policy <
  286. boost::math::policies::domain_error<boost::math::policies::ignore_error>,
  287. boost::math::policies::overflow_error<boost::math::policies::ignore_error>,
  288. boost::math::policies::underflow_error<boost::math::policies::ignore_error>,
  289. boost::math::policies::denorm_error<boost::math::policies::ignore_error>,
  290. boost::math::policies::pole_error<boost::math::policies::ignore_error>,
  291. boost::math::policies::evaluation_error<boost::math::policies::ignore_error>
  292. > ignore_all_policy;
  293. // Test some bad parameters to the function, with default policy and also with ignore_all policy.
  294. #ifndef BOOST_NO_EXCEPTIONS
  295. BOOST_CHECK_THROW(lambert_w0<RealType>(-1.), std::domain_error);
  296. BOOST_CHECK_THROW(lambert_wm1<RealType>(-1.), std::domain_error);
  297. if (std::numeric_limits<RealType>::has_quiet_NaN)
  298. {
  299. BOOST_CHECK_THROW(lambert_w0<RealType>(std::numeric_limits<RealType>::quiet_NaN()), std::domain_error); // Would be NaN.
  300. //BOOST_CHECK_EQUAL(lambert_w0<RealType>(std::numeric_limits<RealType>::quiet_NaN(), ignore_all_policy()), std::numeric_limits<RealType>::quiet_NaN()); // Should be NaN.
  301. // Fails as NaN != NaN by definition.
  302. BOOST_CHECK(boost::math::isnan(lambert_w0<RealType>(std::numeric_limits<RealType>::quiet_NaN(), ignore_all_policy())));
  303. //BOOST_MATH_CHECK_EQUAL(boost::math::lambert_w0<RealType>(std::numeric_limits<RealType>::infinity(), ignore_all_policy()), std::numeric_limits<RealType::infinity()); // infinity.
  304. }
  305. // BOOST_CHECK_THROW(lambert_w0<RealType>(std::numeric_limits<RealType>::infinity()), std::domain_error); // Was if infinity should throw, now infinity.
  306. BOOST_CHECK_THROW(lambert_w0<RealType>(-static_cast<RealType>(0.4)), std::domain_error); // Would be complex.
  307. #else // No exceptions, so set policy to ignore and check result is NaN.
  308. 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.
  309. BOOST_MATH_CHECK_EQUAL(boost::math::lambert_w0<RealType>(std::numeric_limits<RealType>::infinity(), ignore_all_policy()), std::numeric_limits<RealType::infinity()); // infinity.
  310. BOOST_MATH_CHECK_EQUAL(boost::math::lambert_w0<RealType>(std::numeric_limits<RealType>::infinity(), ignore_all_policy()), std::numeric_limits<RealType::infinity()); // infinity.
  311. #endif
  312. std::cout << "\nTesting type " << typeid(RealType).name() << std::endl;
  313. int epsilons = 2;
  314. if (std::numeric_limits<RealType>::digits > 53)
  315. { // Multiprecision types.
  316. epsilons *= 8; // (Perhaps needed because need slightly longer (55) reference values?).
  317. }
  318. RealType tolerance = boost::math::tools::epsilon<RealType>() * epsilons; // 2 eps as a fraction.
  319. std::cout << "Tolerance " << epsilons << " * epsilon == " << tolerance << std::endl;
  320. #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
  321. std::cout << "Precision " << std::numeric_limits<RealType>::digits10 << " decimal digits, max_digits10 = " << std::numeric_limits <RealType>::max_digits10<< std::endl;
  322. // std::cout.precision(std::numeric_limits<RealType>::digits10);
  323. std::cout.precision(std::numeric_limits <RealType>::max_digits10);
  324. #endif
  325. std::cout.setf(std::ios_base::showpoint); // show trailing significant zeros.
  326. std::cout << "-exp(-1) = " << -exp_minus_one<RealType>() << std::endl;
  327. wolfram_test_near_singularity<RealType>();
  328. wolfram_test_large<RealType>();
  329. wolfram_test_small_neg<RealType>();
  330. wolfram_test_small_pos<RealType>();
  331. wolfram_test_moderate_values<RealType>();
  332. // Test at singularity.
  333. // RealType test_value = BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527);
  334. RealType singular_value = -exp_minus_one<RealType>();
  335. // -exp(-1) = -0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527
  336. // lambert_w0[-0.367879441171442321595523770161460867445811131031767834] == -1
  337. // -0.36787945032119751
  338. RealType minus_one_value = BOOST_MATH_TEST_VALUE(RealType, -1.);
  339. //std::cout << "singular_value " << singular_value << ", expected Lambert W = " << minus_one_value << std::endl;
  340. BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) = -0.367879450 = -1max
  341. lambert_w0(singular_value),
  342. minus_one_value,
  343. tolerance); // OK
  344. BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) ~= -0.367879450 == -1
  345. lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527)),
  346. BOOST_MATH_TEST_VALUE(RealType, -1.),
  347. tolerance);
  348. BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) ~= -0.367879450 == -1
  349. lambert_w0<RealType>(-exp_minus_one<RealType>()),
  350. BOOST_MATH_TEST_VALUE(RealType, -1.),
  351. tolerance);
  352. // Tests with some spot values computed using
  353. // https://www.wolframalpha.com/input
  354. // For example: N[lambert_w[1], 50] outputs:
  355. // 0.56714329040978387299996866221035554975381578718651
  356. // At branch junction singularity.
  357. BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) ~= -0.367879450 == -1
  358. lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527)),
  359. BOOST_MATH_TEST_VALUE(RealType, -1.),
  360. tolerance);
  361. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.1)),
  362. BOOST_MATH_TEST_VALUE(RealType, 0.091276527160862264299895721423179568653119224051472),
  363. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(0.2)
  364. tolerance);
  365. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.2)),
  366. BOOST_MATH_TEST_VALUE(RealType, 0.16891597349910956511647490370581839872844691351073),
  367. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(0.2)
  368. tolerance);
  369. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.5)),
  370. BOOST_MATH_TEST_VALUE(RealType, 0.351733711249195826024909300929951065171464215517111804046),
  371. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(0.5)
  372. tolerance);
  373. BOOST_CHECK_CLOSE_FRACTION(
  374. lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.)),
  375. BOOST_MATH_TEST_VALUE(RealType, 0.56714329040978387299996866221035554975381578718651),
  376. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(1)
  377. tolerance);
  378. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 2.)),
  379. BOOST_MATH_TEST_VALUE(RealType, 0.852605502013725491346472414695317466898453300151403508772),
  380. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(2.)
  381. tolerance);
  382. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 3.)),
  383. BOOST_MATH_TEST_VALUE(RealType, 1.049908894964039959988697070552897904589466943706341452932),
  384. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(3.)
  385. tolerance);
  386. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 5.)),
  387. BOOST_MATH_TEST_VALUE(RealType, 1.326724665242200223635099297758079660128793554638047479789),
  388. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(0.5)
  389. tolerance);
  390. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 6.)),
  391. BOOST_MATH_TEST_VALUE(RealType, 1.432404775898300311234078007212058694786434608804302025655),
  392. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(6)
  393. tolerance);
  394. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 100.)),
  395. BOOST_MATH_TEST_VALUE(RealType, 3.3856301402900501848882443645297268674916941701578),
  396. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(100)
  397. tolerance);
  398. if (std::numeric_limits<RealType>::has_infinity)
  399. {
  400. BOOST_CHECK_THROW(lambert_w0(std::numeric_limits<RealType>::infinity()), std::overflow_error); // If should throw exception for infinity.
  401. //BOOST_CHECK_EQUAL(lambert_w0(std::numeric_limits<RealType>::infinity()), +std::numeric_limits<RealType>::infinity()); // message is:
  402. // Error in "test_types": class boost::exception_detail::clone_impl<struct boost::exception_detail::error_info_injector<class std::overflow_error> > :
  403. // Error in function boost::math::lambert_w0<RealType>(<RealType>) : Argument z is infinite!
  404. //BOOST_CHECK_EQUAL(lambert_w0(std::numeric_limits<RealType>::infinity()), +std::numeric_limits<RealType>::infinity()); // If infinity allowed.
  405. BOOST_CHECK_THROW(lambert_wm1(std::numeric_limits<RealType>::infinity()), std::domain_error); // Infinity NOT allowed at all (not an edge case).
  406. }
  407. if (std::numeric_limits<RealType>::has_quiet_NaN)
  408. { // Argument Z == NaN is always an throwable error for both branches.
  409. // BOOST_CHECK_EQUAL(lambert_w0(std::numeric_limits<RealType>::quiet_NaN()), +std::numeric_limits<RealType>::infinity()); // message is:
  410. // Error in function boost::math::lambert_w0<RealType>(<RealType>): Argument z is NaN!
  411. BOOST_CHECK_THROW(lambert_w0(std::numeric_limits<RealType>::quiet_NaN()), std::domain_error);
  412. BOOST_CHECK_THROW(lambert_wm1(std::numeric_limits<RealType>::quiet_NaN()), std::domain_error);
  413. }
  414. // denorm - but might be == min or zero?
  415. if (std::numeric_limits<RealType>::has_denorm == true)
  416. { // Might also return infinity like z == 0?
  417. BOOST_CHECK_THROW(lambert_wm1(std::numeric_limits<RealType>::denorm_min()), std::overflow_error);
  418. }
  419. // Tests of Lambert W-1 branch.
  420. BOOST_CHECK_CLOSE_FRACTION( // Check -exp(-1) ~= -0.367879450 == -1 at the singularity branch point.
  421. lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144232159552377016146086744581113103176783450783680169746149574489980335714727434591964374662732527)),
  422. BOOST_MATH_TEST_VALUE(RealType, -1.),
  423. tolerance);
  424. // Near singularity and using series approximation.
  425. // N[productlog(-1, -0.36), 50] = -1.2227701339785059531429380734238623131735264411311
  426. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.36)),
  427. BOOST_MATH_TEST_VALUE(RealType, -1.2227701339785059531429380734238623131735264411311),
  428. 10 * tolerance); // tolerance OK for quad
  429. // -1.2227701339785059531429380734238623131735264411311
  430. // -1.222770133978505953142938073423862313173526441131033
  431. // Just using series approximation (switch at -0.35).
  432. // N[productlog(-0.351), 50] = -0.72398644140937651483634596143951001600417138085814
  433. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.351)),
  434. BOOST_MATH_TEST_VALUE(RealType, -0.72398644140937651483634596143951001600417138085814),
  435. // 2 * tolerance); // Note 2 * tolerance for PB fukushima
  436. // got -0.723986441409376931150560229265736446 without Halley
  437. // exp -0.72398644140937651483634596143951001
  438. // got -0.72398644140937651483634596143951029 with Halley
  439. 10 * tolerance); // expect -0.72398644140937651 float -0.723987103 needs 10 * tolerance
  440. // 2 * tolerance is fine for double and up.
  441. // Float is OK
  442. // Same for W-1 branch
  443. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.351)),
  444. BOOST_MATH_TEST_VALUE(RealType, -1.3385736984773431852492145715526995809854973408320),
  445. 10 * tolerance); // 2 tolerance OK for quad
  446. // Near singularity and NOT using series approximation (switch at -0.35)
  447. // N[productlog(-1, -0.34), 50]
  448. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.34)),
  449. BOOST_MATH_TEST_VALUE(RealType, -1.4512014851325470735077533710339268100722032730024),
  450. 10 * tolerance); // tolerance OK for quad
  451. //
  452. // Decreasing z until near zero (small z) .
  453. //N[productlog(-1, -0.3), 50] = -1.7813370234216276119741702815127452608215583564545
  454. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.3)),
  455. BOOST_MATH_TEST_VALUE(RealType, -1.7813370234216276119741702815127452608215583564545),
  456. 2 * tolerance);
  457. // -1.78133702342162761197417028151274526082155835645446
  458. //N[productlog(-1, -0.2), 50] = -2.5426413577735264242938061566618482901614749075294
  459. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.2)),
  460. BOOST_MATH_TEST_VALUE(RealType, -2.5426413577735264242938061566618482901614749075294),
  461. 2 * tolerance);
  462. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.1)),
  463. BOOST_MATH_TEST_VALUE(RealType, -3.577152063957297218409391963511994880401796257793),
  464. tolerance);
  465. //N[productlog(-1, -0.01), 50] = -6.4727751243940046947410578927244880371043455902257
  466. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.01)),
  467. BOOST_MATH_TEST_VALUE(RealType, -6.4727751243940046947410578927244880371043455902257),
  468. tolerance);
  469. // N[productlog(-1, -0.001), 50] = -9.1180064704027401212583371820468142742704349737639
  470. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.001)),
  471. BOOST_MATH_TEST_VALUE(RealType, -9.1180064704027401212583371820468142742704349737639),
  472. tolerance);
  473. // N[productlog(-1, -0.000001), 50] = -16.626508901372473387706432163984684996461726803805
  474. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.000001)),
  475. BOOST_MATH_TEST_VALUE(RealType, -16.626508901372473387706432163984684996461726803805),
  476. tolerance);
  477. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-12)),
  478. BOOST_MATH_TEST_VALUE(RealType, -31.067172842017230842039496250208586707880448763222),
  479. tolerance);
  480. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-25)),
  481. BOOST_MATH_TEST_VALUE(RealType, -61.686695602074505366866968627049381352503620377944),
  482. tolerance);
  483. // z nearly too small.
  484. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -2e-26)),
  485. BOOST_MATH_TEST_VALUE(RealType, -63.322302839923597803393585145387854867226970485197),
  486. tolerance* 2);
  487. // z very nearly too small. G(k=64) g[63] = -1.0264389699511303e-26 to using 1.027e-26
  488. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1.027e-26)),
  489. BOOST_MATH_TEST_VALUE(RealType, -63.999444896732265186957073549916026532499356695343),
  490. tolerance);
  491. // So -64 is the most negative value that can be determined using lookup.
  492. // N[productlog(-1, -1.0264389699511303 * 10^-26 ), 50] -63.999999999999997947255011093606206983577811736472 == -64
  493. // G[k=64] = g[63] = -1.0264389699511303e-26
  494. // z too small for G(k=64) g[63] = -1.0264389699511303e-26 to using 1.027e-26
  495. // N[productlog(-1, -10 ^ -26), 50] = -31.067172842017230842039496250208586707880448763222
  496. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-26)),
  497. BOOST_MATH_TEST_VALUE(RealType, -64.026509628385889681156090340691637712441162092868),
  498. tolerance); // -64.0265121
  499. if (std::numeric_limits<RealType>::has_infinity)
  500. {
  501. BOOST_CHECK_EQUAL(lambert_wm1(0), -std::numeric_limits<RealType>::infinity());
  502. }
  503. if (std::numeric_limits<RealType>::has_quiet_NaN)
  504. {
  505. // BOOST_CHECK_EQUAL(lambert_w0(std::numeric_limits<RealType>::quiet_NaN()), +std::numeric_limits<RealType>::infinity()); // message is:
  506. // Error in function boost::math::lambert_w0<RealType>(<RealType>): Argument z is NaN!
  507. BOOST_CHECK_THROW(lambert_wm1(std::numeric_limits<RealType>::quiet_NaN()), std::domain_error);
  508. }
  509. // W0 Tests for too big and too small to use lookup table.
  510. // Exactly W = 64, not enough to be OK for lookup.
  511. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 3.9904954117194348050619127737142206366920907815909119e+29)),
  512. BOOST_MATH_TEST_VALUE(RealType, 64.0),
  513. tolerance);
  514. // Just below z for F[64]
  515. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 3.99045411719434e+29)),
  516. BOOST_MATH_TEST_VALUE(RealType, 63.999989810930513468726486827408823607175844852495), tolerance);
  517. // Fails for quad_float -1.22277013397850595265
  518. // -1.22277013397850595319
  519. // Just too big, so using log approx and Halley refinement.
  520. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 4e+29)),
  521. BOOST_MATH_TEST_VALUE(RealType, 64.002342375637950350970694519073803643686041499677),
  522. tolerance);
  523. // Check at reduced precision.
  524. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 4e+29), policy<digits2<11> >()),
  525. BOOST_MATH_TEST_VALUE(RealType, 64.002342375637950350970694519073803643686041499677),
  526. 0.00002); // 0.00001 fails.
  527. // Tests to ensure that all JM rational polynomials are being checked.
  528. // 1st polynomal if (z < 0.5) // 0.05 < z < 0.5
  529. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.49)),
  530. BOOST_MATH_TEST_VALUE(RealType, 0.3465058086974944293540338951489158955895910665452626949),
  531. tolerance);
  532. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.051)),
  533. BOOST_MATH_TEST_VALUE(RealType, 0.04858156174600359264950777241723801201748517590507517888),
  534. tolerance);
  535. // 2st polynomal if 0.5 < z < 2
  536. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.51)),
  537. BOOST_MATH_TEST_VALUE(RealType, 0.3569144916935871518694242462560450385494399307379277704),
  538. tolerance);
  539. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.9)),
  540. BOOST_MATH_TEST_VALUE(RealType, 0.8291763302658400337004358009672187071638421282477162293),
  541. tolerance);
  542. // 3rd polynomials 2 < z < 6
  543. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 2.1)),
  544. BOOST_MATH_TEST_VALUE(RealType, 0.8752187586805470099843211502166029752154384079916131962),
  545. tolerance);
  546. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 5.9)),
  547. BOOST_MATH_TEST_VALUE(RealType, 1.422521411785098213935338853943459424120416844150520831),
  548. tolerance);
  549. // 4th polynomials 6 < z < 18
  550. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 6.1)),
  551. BOOST_MATH_TEST_VALUE(RealType, 1.442152194116056579987235881273412088690824214100254315),
  552. tolerance);
  553. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 17.9)),
  554. BOOST_MATH_TEST_VALUE(RealType, 2.129100923757568114366514708174691237123820852409339147),
  555. tolerance);
  556. // 5th polynomials if (z < 9897.12905874) // 2.8 < log(z) < 9.2
  557. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 18.1)),
  558. BOOST_MATH_TEST_VALUE(RealType, 2.136665501382339778305178680563584563343639180897328666),
  559. tolerance);
  560. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 9897.)),
  561. BOOST_MATH_TEST_VALUE(RealType, 7.222751047988674263127929506116648714752441161828893633),
  562. tolerance);
  563. // 6th polynomials if (z < 7.896296e+13) // 9.2 < log(z) <= 32
  564. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 9999.)),
  565. BOOST_MATH_TEST_VALUE(RealType, 7.231758181708737258902175236106030961433080976032516996),
  566. tolerance);
  567. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 7.7e+13)),
  568. BOOST_MATH_TEST_VALUE(RealType, 28.62069643025822480911439831021393125282095606713326376),
  569. tolerance);
  570. // 7th polynomial // 32 < log(z) < 100
  571. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 8.0e+18)),
  572. BOOST_MATH_TEST_VALUE(RealType, 39.84107480517853176296156400093560722439428484537515586),
  573. tolerance);
  574. // Largest 32-bit float. (Larger values for other types tested using max())
  575. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.e38)),
  576. BOOST_MATH_TEST_VALUE(RealType, 83.07844821316409592720410446942538465411465113447713574),
  577. tolerance);
  578. // Using z small series function if z < 0.05 if (z < -0.051) -0.27 < z < -0.051
  579. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.28)),
  580. BOOST_MATH_TEST_VALUE(RealType, -0.4307588745271127579165306568413721388196459822705155385),
  581. tolerance);
  582. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.25)),
  583. BOOST_MATH_TEST_VALUE(RealType, -0.3574029561813889030688111040559047533165905550760120436),
  584. tolerance);
  585. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, +0.25)),
  586. BOOST_MATH_TEST_VALUE(RealType, 0.2038883547022401644431818313271398701493524772101596350),
  587. tolerance);
  588. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.051)), // just above 0.05 cutoff.
  589. BOOST_MATH_TEST_VALUE(RealType, -0.05382002772543396036830469500362485089791914689728115249),
  590. tolerance * 4);
  591. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.05)), // at cutoff.
  592. BOOST_MATH_TEST_VALUE(RealType, -0.05270598355154634795995650617915721289427674396592395160),
  593. tolerance * 8);
  594. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.049)), // Just below cutoff.
  595. BOOST_MATH_TEST_VALUE(RealType, 0.04676143671340832342497289393737051868103596756298863555),
  596. tolerance * 4);
  597. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.01)),
  598. BOOST_MATH_TEST_VALUE(RealType, 0.009901473843595011885336326816570107953627746494917415483),
  599. tolerance);
  600. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.01)),
  601. BOOST_MATH_TEST_VALUE(RealType, -0.01010152719853875327292018767138623973670903993475235877),
  602. tolerance);
  603. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.049)),
  604. BOOST_MATH_TEST_VALUE(RealType, -0.05159448479219405354564920228913331280713177046648170658),
  605. tolerance * 8);
  606. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1e-6)),
  607. BOOST_MATH_TEST_VALUE(RealType, 9.999990000014999973333385416558666900096702096424344715e-7),
  608. tolerance);
  609. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -1e-6)),
  610. BOOST_MATH_TEST_VALUE(RealType, -1.000001000001500002666671875010800023343107568372593753e-6),
  611. tolerance);
  612. // Near Smallest float.
  613. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1e-38)),
  614. BOOST_MATH_TEST_VALUE(RealType, 9.99999999999999999999999999999999999990000000000000000e-39),
  615. tolerance);
  616. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -1e-38)),
  617. BOOST_MATH_TEST_VALUE(RealType, -1.000000000000000000000000000000000000010000000000000000e-38),
  618. tolerance);
  619. // Similar 'too near zero' tests for W-1 branch.
  620. // lambert_wm1(-1.0264389699511283e-26) = -64.000000000000000
  621. // Exactly z for W=-64
  622. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1.026438969951128225904695701851094643838952857740385870e-26)),
  623. BOOST_MATH_TEST_VALUE(RealType, -64.000000000000000000000000000000000000),
  624. 2 * tolerance);
  625. // Just more negative than G[64 max] = wm1zs[63] so can't use lookup table.
  626. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1.5e-27)),
  627. BOOST_MATH_TEST_VALUE(RealType, -65.953279000145077719128800110134854577850889171784),
  628. tolerance); // -65.9532776
  629. // Just less negative than G[64 max] = wm1zs[63] so can use lookup table.
  630. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1.1e-26)),
  631. BOOST_MATH_TEST_VALUE(RealType, -63.929686062157630858625440758283127600360210072859),
  632. tolerance);
  633. // N[productlog(-1, -10 ^ -26), 50] = -31.067172842017230842039496250208586707880448763222
  634. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-26)),
  635. BOOST_MATH_TEST_VALUE(RealType, -64.026509628385889681156090340691637712441162092868),
  636. tolerance);
  637. // 1e-28 is too small
  638. // N[productlog(-1, -10 ^ -28), 50] = -31.067172842017230842039496250208586707880448763222
  639. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-28)),
  640. BOOST_MATH_TEST_VALUE(RealType, -68.702163291525429160769761667024460023336801014578),
  641. tolerance);
  642. // Check for overflow when using a double (including when using for approximate value for refinement for higher precision).
  643. // N[productlog(-1, -10 ^ -30), 50] = -73.373110313822976797067478758120874529181611813766
  644. //BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e30)),
  645. // BOOST_MATH_TEST_VALUE(RealType, -73.373110313822976797067478758120874529181611813766),
  646. // tolerance);
  647. //unknown location : fatal error : in "test_types" :
  648. //class boost::exception_detail::clone_impl<struct boost::exception_detail::error_info_injector<class std::domain_error> >
  649. // : Error in function boost::math::lambert_wm1<RealType>(<RealType>) :
  650. // Argument z = -1.00000002e+30 out of range(z < -exp(-1) = -3.6787944) for Lambert W - 1 branch!
  651. BOOST_CHECK_THROW(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e30)), std::domain_error);
  652. // Too negative
  653. BOOST_CHECK_THROW(lambert_wm1(RealType(-0.5)), std::domain_error);
  654. // This fails for fixed_point type used for other tests because out of range?
  655. //BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.0e6)),
  656. //BOOST_MATH_TEST_VALUE(RealType, 11.383358086140052622000156781585004289033774706019),
  657. //// Output from https://www.wolframalpha.com/input/?i=lambert_w0(1e6)
  658. //// tolerance * 1000); // fails for fixed_point type exceeds 0.00015258789063
  659. // // 15.258789063
  660. // // 11.383346558
  661. // tolerance * 100000);
  662. // So need to use some spot tests for specific types, or use a bigger fixed_point type.
  663. // Check zero.
  664. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.0)),
  665. BOOST_MATH_TEST_VALUE(RealType, 0.0),
  666. tolerance);
  667. // these fail for cpp_dec_float_50
  668. // '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>'
  669. // : no appropriate default constructor available
  670. // TODO ???????????
  671. } // template <class RealType>void test_spots(RealType)
  672. BOOST_AUTO_TEST_CASE( test_types )
  673. {
  674. BOOST_MATH_CONTROL_FP;
  675. // BOOST_TEST_MESSAGE output only appears if command line has --log_level="message"
  676. // or call set_threshold_level function:
  677. boost::unit_test_framework::unit_test_log.set_threshold_level(boost::unit_test_framework::log_messages);
  678. BOOST_TEST_MESSAGE("\nTest Lambert W function for several types.");
  679. BOOST_TEST_MESSAGE(show_versions()); // Full version of Boost, STL and compiler info.
  680. #ifndef BOOST_MATH_TEST_MULTIPRECISION
  681. // Fundamental built-in types:
  682. test_spots(0.0F); // float
  683. test_spots(0.0); // double
  684. #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  685. if (sizeof(long double) > sizeof(double))
  686. { // Avoid pointless re-testing if double and long double are identical (for example, MSVC).
  687. test_spots(0.0L); // long double
  688. }
  689. test_spots(boost::math::concepts::real_concept(0));
  690. #endif
  691. #else // BOOST_MATH_TEST_MULTIPRECISION
  692. // Multiprecision types:
  693. #if BOOST_MATH_TEST_MULTIPRECISION == 1
  694. test_spots(static_cast<boost::multiprecision::cpp_bin_float_double_extended>(0));
  695. #endif
  696. #if BOOST_MATH_TEST_MULTIPRECISION == 2
  697. test_spots(static_cast<boost::multiprecision::cpp_bin_float_quad>(0));
  698. #endif
  699. #if BOOST_MATH_TEST_MULTIPRECISION == 3
  700. test_spots(static_cast<boost::multiprecision::cpp_bin_float_50>(0));
  701. #endif
  702. #endif // ifdef BOOST_MATH_TEST_MULTIPRECISION
  703. #ifdef BOOST_MATH_TEST_FLOAT128
  704. std::cout << "\nBOOST_MATH_TEST_FLOAT128 defined for float128 tests." << std::endl;
  705. #ifdef BOOST_HAS_FLOAT128
  706. // GCC and Intel only.
  707. // Requires link to libquadmath library, see
  708. // http://www.boost.org/doc/libs/release/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/float128.html
  709. // for example:
  710. // 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
  711. using boost::multiprecision::float128;
  712. std::cout << "BOOST_HAS_FLOAT128" << std::endl;
  713. std::cout.precision(std::numeric_limits<float128>::max_digits10);
  714. test_spots(static_cast<float128>(0));
  715. #endif // BOOST_HAS_FLOAT128
  716. #else
  717. std::cout << "\nBOOST_MATH_TEST_FLOAT128 NOT defined so NO float128 tests." << std::endl;
  718. #endif // #ifdef BOOST_MATH_TEST_FLOAT128
  719. } // BOOST_AUTO_TEST_CASE( test_types )
  720. BOOST_AUTO_TEST_CASE( test_range_of_double_values )
  721. {
  722. using boost::math::constants::exp_minus_one;
  723. using boost::math::lambert_w0;
  724. BOOST_TEST_MESSAGE("\nTest Lambert W function type double for range of values.");
  725. // Want to test almost largest value.
  726. // test_value = (std::numeric_limits<RealType>::max)() / 4;
  727. // std::cout << std::setprecision(std::numeric_limits<RealType>::max_digits10) << "Max value = " << test_value << std::endl;
  728. // Can't use a test like this for all types because max_value depends on RealType
  729. // and thus the expected result of lambert_w0 does too.
  730. //BOOST_CHECK_CLOSE_FRACTION(lambert_w0<RealType>(test_value),
  731. // BOOST_MATH_TEST_VALUE(RealType, ???),
  732. // tolerance);
  733. // So this section just tests a single type, say IEEE 64-bit double, for a range of spot values.
  734. typedef double RealType; // Some tests assume type is double.
  735. int epsilons = 1;
  736. RealType tolerance = boost::math::tools::epsilon<RealType>() * epsilons; // 2 eps as a fraction.
  737. std::cout << "Tolerance " << epsilons << " * epsilon == " << tolerance << std::endl;
  738. #ifndef BOOST_MATH_TEST_MULTIPRECISION
  739. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.0e-6)),
  740. BOOST_MATH_TEST_VALUE(RealType, 9.9999900000149999733333854165586669000967020964243e-7),
  741. // Output from https://www.wolframalpha.com/input/ N[lambert_w[1e-6],50])
  742. tolerance);
  743. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.0001)),
  744. BOOST_MATH_TEST_VALUE(RealType, 0.000099990001499733385405869000452213835767629477903460),
  745. // Output from https://www.wolframalpha.com/input/ N[lambert_w[0.001],50])
  746. tolerance);
  747. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.001)),
  748. BOOST_MATH_TEST_VALUE(RealType, 0.00099900149733853088995782787410778559957065467928884),
  749. // Output from https://www.wolframalpha.com/input/ N[lambert_w[0.001],50])
  750. tolerance);
  751. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.01)),
  752. BOOST_MATH_TEST_VALUE(RealType, 0.0099014738435950118853363268165701079536277464949174),
  753. // Output from https://www.wolframalpha.com/input/ N[lambert_w[0.01],50])
  754. tolerance * 25); // <<< Needs a much bigger tolerance???
  755. // 0.0099014738435951096 this test max_digits10
  756. // 0.00990147384359511 digits10
  757. // 0.0099014738435950118 wolfram
  758. // 0.00990147384359501 wolfram digits10
  759. // 0.0099014738435950119 N[lambert_w[0.01],17]
  760. // 0.00990147384359501 N[lambert_w[0.01],15] which really is more different than expected.
  761. // 0.00990728209160670 approx
  762. // 0.00990147384359511 previous
  763. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.05)),
  764. BOOST_MATH_TEST_VALUE(RealType, 0.047672308600129374726388900514160870747062965933891),
  765. // Output from https://www.wolframalpha.com/input/ N[lambert_w[0.01],50])
  766. tolerance);
  767. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 0.1)),
  768. BOOST_MATH_TEST_VALUE(RealType, 0.091276527160862264299895721423179568653119224051472),
  769. // Output from https://www.wolframalpha.com/input/ N[lambert_w[1],50])
  770. tolerance);
  771. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.)),
  772. BOOST_MATH_TEST_VALUE(RealType, 0.56714329040978387299996866221035554975381578718651),
  773. // Output from https://www.wolframalpha.com/input/ N[lambert_w[1],50])
  774. tolerance);
  775. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 2.)),
  776. BOOST_MATH_TEST_VALUE(RealType, 0.852605502013725491346472414695317466898453300151403508772),
  777. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(2.)
  778. tolerance);
  779. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 3.)),
  780. BOOST_MATH_TEST_VALUE(RealType, 1.049908894964039959988697070552897904589466943706341452932),
  781. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(3.)
  782. tolerance);
  783. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 5.)),
  784. BOOST_MATH_TEST_VALUE(RealType, 1.326724665242200223635099297758079660128793554638047479789),
  785. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(0.5)
  786. tolerance);
  787. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 6.)),
  788. BOOST_MATH_TEST_VALUE(RealType, 1.432404775898300311234078007212058694786434608804302025655),
  789. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(6)
  790. tolerance);
  791. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 10.)),
  792. BOOST_MATH_TEST_VALUE(RealType, 1.7455280027406993830743012648753899115352881290809),
  793. // Output from https://www.wolframalpha.com/input/ N[lambert_w[10],50])
  794. tolerance);
  795. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 100.)),
  796. BOOST_MATH_TEST_VALUE(RealType, 3.3856301402900501848882443645297268674916941701578),
  797. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(100)
  798. tolerance);
  799. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1000.)),
  800. BOOST_MATH_TEST_VALUE(RealType, 5.2496028524015962271260563196973062825214723860596),
  801. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(1000)
  802. tolerance);
  803. // This fails for fixed_point type used for other tests because out of range of the type?
  804. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, 1.0e6)),
  805. BOOST_MATH_TEST_VALUE(RealType, 11.383358086140052622000156781585004289033774706019),
  806. // Output from https://www.wolframalpha.com/input/?i=lambert_w0(1e6)
  807. tolerance); //
  808. // Tests for double only near the max and the singularity where Lambert_w estimates are less precise.
  809. if (std::numeric_limits<RealType>::is_specialized)
  810. { // is_specialized means that can use numeric_limits for tests.
  811. // Check near std::numeric_limits<>::max() for type.
  812. //std::cout << std::setprecision(std::numeric_limits<RealType>::max_digits10)
  813. // << (std::numeric_limits<double>::max)() // == 1.7976931348623157e+308
  814. // << " " << (std::numeric_limits<double>::max)()/4 // == 4.4942328371557893e+307
  815. // << std::endl;
  816. // All these result in faulty error message
  817. // 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.
  818. // I:\modular - boost\libs\math\test\test_lambert_w.cpp(456) : last checkpoint
  819. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(1.7976931348623157e+308 ), // max_value for IEEE 64-bit double.
  820. static_cast<double>(703.2270331047701868711791887193075929608934699575820028L),
  821. // N[productlog[0, 1.7976931348623157*10^308 /2],50] == 702.53487067487671916110655783739076368512998658347
  822. tolerance);
  823. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(1.7976931348623157e+308 / 2), // max_value/2 for IEEE 64-bit double.
  824. static_cast<double>(702.53487067487671916110655783739076368512998658347L),
  825. // N[productlog[0, 1.7976931348623157*10^308 /2],50] == 702.53487067487671916110655783739076368512998658347
  826. tolerance);
  827. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(1.7976931348623157e+308 /4), // near max_value/4 for IEEE 64-bit double.
  828. static_cast<double>(701.8427092142920014223182853764045476L),
  829. // N[productlog(0, 1.7976931348623157* 10^308 /4 ), 37] =701.8427092142920014223182853764045476
  830. // N[productlog(0, 0.25 * 1.7976931348623157*10^307), 37]
  831. tolerance);
  832. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(4.4942328371557893e+307), // max_value/4 for IEEE 64-bit double.
  833. static_cast<double>(701.84270921429200143342782556643059L),
  834. // N[lambert_w[4.4942328371557893e+307], 35] == 701.8427092142920014334278255664305887
  835. // as a double == 701.83341468208209
  836. // Lambert computed 702.02379914670587
  837. 0.000003); // OK Much less precise at the max edge???
  838. BOOST_CHECK_CLOSE_FRACTION(lambert_w0((std::numeric_limits<double>::max)()), // max_value for IEEE 64-bit double.
  839. static_cast<double>(703.2270331047701868711791887193075930),
  840. // N[productlog(0, 1.7976931348623157* 10^308), 37] = 703.2270331047701868711791887193075930
  841. // 703.22700325995515 lambert W
  842. // 703.22703310477016 Wolfram
  843. tolerance * 2e8); // OK but much less accurate near max.
  844. // Compare precisions very close to the singularity.
  845. // This test value is one epsilon close to the singularity at -exp(-1) * z
  846. // (below which the result has a non-zero imaginary part).
  847. RealType test_value = -exp_minus_one<RealType>();
  848. test_value += (std::numeric_limits<RealType>::epsilon() * 1);
  849. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(test_value),
  850. BOOST_MATH_TEST_VALUE(RealType, -0.99999996349975895),
  851. tolerance * 1000000000);
  852. // -0.99999996788201051
  853. // -0.99999996349975895
  854. // Would not expect to get a result closer than sqrt(epsilon)?
  855. } // if (std::numeric_limits<RealType>::is_specialized)
  856. // Can only compare float_next for specific type T = double.
  857. // Comparison with Wolfram N[productlog(0,-0.36787944117144228 ), 17]
  858. // Note big loss of precision and big tolerance needed to pass.
  859. BOOST_CHECK_CLOSE_FRACTION( // Check float_next(-exp(-1) )
  860. lambert_w0(BOOST_MATH_TEST_VALUE(double, -0.36787944117144228)),
  861. BOOST_MATH_TEST_VALUE(RealType, -0.99999998496215738),
  862. 1e8 * tolerance); // diff 6.03558e-09 v 2.2204460492503131e-16
  863. BOOST_CHECK_CLOSE_FRACTION( // Check float_next(float_next(-exp(-1) ))
  864. lambert_w0(BOOST_MATH_TEST_VALUE(double, -0.36787944117144222)),
  865. BOOST_MATH_TEST_VALUE(RealType, -0.99999997649828679),
  866. 5e7 * tolerance);// diff 2.30785e-09 v 2.2204460492503131e-16
  867. // Compare with previous PB/FK computations at double precision.
  868. BOOST_CHECK_CLOSE_FRACTION( // Check float_next(-exp(-1) )
  869. lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144228)),
  870. BOOST_MATH_TEST_VALUE(RealType, -0.99999997892657588),
  871. tolerance); // diff 6.03558e-09 v 2.2204460492503131e-16
  872. BOOST_CHECK_CLOSE_FRACTION( // Check float_next(float_next(-exp(-1) ))
  873. lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.36787944117144222)),
  874. BOOST_MATH_TEST_VALUE(RealType, -0.99999997419043196),
  875. tolerance);// diff 2.30785e-09 v 2.2204460492503131e-16
  876. // z increasingly close to singularity.
  877. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.36)),
  878. BOOST_MATH_TEST_VALUE(RealType, -0.8060843159708177782855213616209920019974599683466713016),
  879. 2 * tolerance); // -0.806084335
  880. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.365)),
  881. BOOST_MATH_TEST_VALUE(RealType, -0.8798200914159538111724840007674053239388642469453350954),
  882. 5 * tolerance); // Note 5 * tolerance
  883. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.3678)),
  884. BOOST_MATH_TEST_VALUE(RealType, -0.9793607149578284774761844434886481686055949229547379368),
  885. 15 * tolerance); // Note 15 * tolerance when this close to singularity.
  886. // Just using series approximation (Fukushima switch at -0.35, but JM at 0.01 of singularity < -0.3679).
  887. // N[productlog(-0.351), 50] = -0.72398644140937651483634596143951001600417138085814
  888. // N[productlog(-0.351), 55] = -0.7239864414093765148363459614395100160041713808581379727
  889. BOOST_CHECK_CLOSE_FRACTION(lambert_w0(BOOST_MATH_TEST_VALUE(RealType, -0.351)),
  890. BOOST_MATH_TEST_VALUE(RealType, -0.72398644140937651483634596143951001600417138085814),
  891. 10 * tolerance); // Note was 2 * tolerance
  892. // Check value just not using near_singularity series approximation (and using rational polynomial instead).
  893. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.3)),
  894. BOOST_MATH_TEST_VALUE(RealType, -1.7813370234216276119741702815127452608215583564545),
  895. // Output from https://www.wolframalpha.com/input/
  896. //N[productlog(-1, -0.3), 50] = -1.7813370234216276119741702815127452608215583564545
  897. tolerance);
  898. // Using table lookup and schroeder with decreasing z to zero.
  899. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.2)),
  900. BOOST_MATH_TEST_VALUE(RealType, -2.5426413577735264242938061566618482901614749075294),
  901. // N[productlog[-1, -0.2],50] -2.5426413577735264242938061566618482901614749075294
  902. tolerance);
  903. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.1)),
  904. BOOST_MATH_TEST_VALUE(RealType, -3.5771520639572972184093919635119948804017962577931),
  905. //N[productlog(-1, -0.1), 50] = -3.5771520639572972184093919635119948804017962577931
  906. tolerance);
  907. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.001)),
  908. BOOST_MATH_TEST_VALUE(RealType, -9.1180064704027401212583371820468142742704349737639),
  909. // N[productlog(-1, -0.001), 50] = -9.1180064704027401212583371820468142742704349737639
  910. tolerance);
  911. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -0.000001)),
  912. BOOST_MATH_TEST_VALUE(RealType, -16.626508901372473387706432163984684996461726803805),
  913. // N[productlog(-1, -0.000001), 50] = -16.626508901372473387706432163984684996461726803805
  914. tolerance);
  915. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-6)),
  916. BOOST_MATH_TEST_VALUE(RealType, -16.626508901372473387706432163984684996461726803805),
  917. // N[productlog(-1, -10 ^ -6), 50] = -16.626508901372473387706432163984684996461726803805
  918. tolerance);
  919. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1.0e-26)),
  920. BOOST_MATH_TEST_VALUE(RealType, -64.026509628385889681156090340691637712441162092868),
  921. // Output from https://www.wolframalpha.com/input/
  922. // N[productlog(-1, -1 * 10^-26 ), 50] = -64.026509628385889681156090340691637712441162092868
  923. tolerance);
  924. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -2e-26)),
  925. BOOST_MATH_TEST_VALUE(RealType, -63.322302839923597803393585145387854867226970485197),
  926. // N[productlog[-1, -2*10^-26],50] = -63.322302839923597803393585145387854867226970485197
  927. tolerance * 2);
  928. // Smaller than lookup table, so must use approx and Halley refinements.
  929. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -1e-30)),
  930. BOOST_MATH_TEST_VALUE(RealType, -73.373110313822976797067478758120874529181611813766),
  931. // N[productlog(-1, -10 ^ -30), 50] = -73.373110313822976797067478758120874529181611813766
  932. tolerance);
  933. // std::numeric_limits<RealType>::min
  934. #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
  935. std::cout.precision(std::numeric_limits<RealType>::max_digits10);
  936. #endif
  937. std::cout << "(std::numeric_limits<RealType>::min)() " << (std::numeric_limits<RealType>::min)() << std::endl;
  938. BOOST_CHECK_CLOSE_FRACTION(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, -2.2250738585072014e-308)),
  939. BOOST_MATH_TEST_VALUE(RealType, -714.96865723796647086868547560654825435542227693935),
  940. // N[productlog[-1, -2.2250738585072014e-308],50] = -714.96865723796647086868547560654825435542227693935
  941. tolerance);
  942. // For z = 0, W = -infinity
  943. if (std::numeric_limits<RealType>::has_infinity)
  944. {
  945. BOOST_CHECK_EQUAL(lambert_wm1(BOOST_MATH_TEST_VALUE(RealType, 0.)),
  946. -std::numeric_limits<RealType>::infinity());
  947. }
  948. #elif BOOST_MATH_TEST_MULTIPRECISION == 2
  949. // Comparison with Wolfram N[productlog(0,-0.36787944117144228 ), 17]
  950. // Using conversion from double to higher precision cpp_bin_float_quad
  951. using boost::multiprecision::cpp_bin_float_quad;
  952. BOOST_CHECK_CLOSE_FRACTION( // Check float_next(-exp(-1) )
  953. lambert_w0(BOOST_MATH_TEST_VALUE(cpp_bin_float_quad, -0.36787944117144228)),
  954. BOOST_MATH_TEST_VALUE(cpp_bin_float_quad, -0.99999998496215738),
  955. tolerance); // OK
  956. BOOST_CHECK_CLOSE_FRACTION( // Check float_next(float_next(-exp(-1) ))
  957. lambert_w0(BOOST_MATH_TEST_VALUE(cpp_bin_float_quad, -0.36787944117144222)),
  958. BOOST_MATH_TEST_VALUE(cpp_bin_float_quad, -0.99999997649828679),
  959. tolerance);// OK
  960. #endif
  961. } // BOOST_AUTO_TEST_CASE(test_range_of_double_values)