File indexing completed on 2025-01-18 09:40:16
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef BOOST_MATH_SF_LAMBERT_W_HPP
0010 #define BOOST_MATH_SF_LAMBERT_W_HPP
0011
0012 #ifdef _MSC_VER
0013 #pragma warning(disable : 4127)
0014 #endif
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 #include <boost/math/tools/config.hpp>
0052 #include <boost/math/policies/error_handling.hpp>
0053 #include <boost/math/policies/policy.hpp>
0054 #include <boost/math/tools/promotion.hpp>
0055 #include <boost/math/special_functions/fpclassify.hpp>
0056 #include <boost/math/special_functions/log1p.hpp> // for log (1 + x)
0057 #include <boost/math/constants/constants.hpp> // For exp_minus_one == 3.67879441171442321595523770161460867e-01.
0058 #include <boost/math/special_functions/next.hpp> // for has_denorm_now
0059 #include <boost/math/special_functions/pow.hpp> // powers with compile time exponent, used in arbitrary precision code.
0060 #include <boost/math/tools/series.hpp> // series functor.
0061
0062 #include <boost/math/tools/rational.hpp> // evaluate_polynomial.
0063 #include <boost/math/tools/precision.hpp> // boost::math::tools::max_value().
0064 #include <boost/math/tools/big_constant.hpp>
0065 #include <boost/math/tools/cxx03_warn.hpp>
0066
0067 #ifndef BOOST_MATH_STANDALONE
0068 #include <boost/lexical_cast.hpp>
0069 #endif
0070
0071 #include <limits>
0072 #include <cmath>
0073 #include <limits>
0074 #include <exception>
0075 #include <type_traits>
0076 #include <cstdint>
0077
0078
0079 #include <iostream>
0080 #include <typeinfo>
0081 #include <boost/math/special_functions/next.hpp> // For float_distance.
0082
0083 using lookup_t = double;
0084
0085
0086
0087 #include <boost/math/special_functions/detail/lambert_w_lookup_table.ipp>
0088
0089 #if defined(__GNUC__) && defined(BOOST_MATH_USE_FLOAT128)
0090
0091
0092
0093
0094
0095
0096 #pragma GCC system_header
0097 #endif
0098
0099 namespace boost {
0100 namespace math {
0101 namespace lambert_w_detail {
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 template <typename T>
0114 inline T lambert_w_halley_step(T w_est, const T z)
0115 {
0116 BOOST_MATH_STD_USING
0117 T e = exp(w_est);
0118 w_est -= 2 * (w_est + 1) * (e * w_est - z) / (z * (w_est + 2) + e * (w_est * (w_est + 2) + 2));
0119 return w_est;
0120 }
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130 template <typename T>
0131 inline T lambert_w_halley_iterate(T w_est, const T z)
0132 {
0133 BOOST_MATH_STD_USING
0134 static const T max_diff = boost::math::tools::root_epsilon<T>() * fabs(w_est);
0135
0136 T w_new = lambert_w_halley_step(w_est, z);
0137 T diff = fabs(w_est - w_new);
0138 while (diff > max_diff)
0139 {
0140 w_est = w_new;
0141 w_new = lambert_w_halley_step(w_est, z);
0142 diff = fabs(w_est - w_new);
0143 }
0144 return w_new;
0145 }
0146
0147
0148
0149
0150 template <typename T>
0151 inline T lambert_w_maybe_halley_iterate(T z, T w, std::false_type const&)
0152 {
0153 return lambert_w_halley_step(z, w);
0154 }
0155
0156 template <typename T>
0157 inline T lambert_w_maybe_halley_iterate(T z, T w, std::true_type const&)
0158 {
0159 return lambert_w_halley_iterate(z, w);
0160 }
0161
0162
0163
0164
0165
0166
0167 template <typename T>
0168 inline double maybe_reduce_to_double(const T& z, const std::true_type&)
0169 {
0170 return static_cast<double>(z);
0171 }
0172
0173 template <typename T>
0174 inline T maybe_reduce_to_double(const T& z, const std::false_type&)
0175 {
0176 return z;
0177 }
0178
0179 template <typename T>
0180 inline double must_reduce_to_double(const T& z, const std::true_type&)
0181 {
0182 return static_cast<double>(z);
0183 }
0184
0185 template <typename T>
0186 inline double must_reduce_to_double(const T& z, const std::false_type&)
0187 {
0188 #ifndef BOOST_MATH_STANDALONE
0189
0190 #ifdef BOOST_MATH_USE_CHARCONV_FOR_CONVERSION
0191
0192
0193 if constexpr (std::is_arithmetic_v<T>)
0194 {
0195 return static_cast<double>(z);
0196 }
0197 else
0198 {
0199 return boost::lexical_cast<double>(z);
0200 }
0201
0202 #else
0203
0204 return boost::lexical_cast<double>(z);
0205
0206 #endif
0207
0208 #else
0209 static_assert(sizeof(T) == 0, "Unsupported in standalone mode: don't know how to cast your number type to a double.");
0210 return 0.0;
0211 #endif
0212 }
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225 template<typename T>
0226 inline T schroeder_update(const T w, const T y)
0227 {
0228
0229
0230
0231
0232
0233
0234
0235
0236 BOOST_MATH_STD_USING
0237 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SCHROEDER
0238 std::streamsize saved_precision = std::cout.precision(std::numeric_limits<T>::max_digits10);
0239 using boost::math::float_distance;
0240 T fd = float_distance<T>(w, y);
0241 std::cout << "Schroder ";
0242 if (abs(fd) < 214748000.)
0243 {
0244 std::cout << " Distance = "<< static_cast<int>(fd);
0245 }
0246 else
0247 {
0248 std::cout << "Difference w - y = " << (w - y) << ".";
0249 }
0250 std::cout << std::endl;
0251 #endif
0252
0253 const T f0 = w - y;
0254 const T f1 = 1 + y;
0255 const T f00 = f0 * f0;
0256 const T f11 = f1 * f1;
0257 const T f0y = f0 * y;
0258 const T result =
0259 w - 4 * f0 * (6 * f1 * (f11 + f0y) + f00 * y) /
0260 (f11 * (24 * f11 + 36 * f0y) +
0261 f00 * (6 * y * y + 8 * f1 * y + f0y));
0262
0263 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SCHROEDER
0264 std::cout << "Schroeder refined " << w << " " << y << ", difference " << w-y << ", change " << w - result << ", to result " << result << std::endl;
0265 std::cout.precision(saved_precision);
0266 #endif
0267
0268 return result;
0269 }
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280 template<typename T>
0281 T lambert_w_singularity_series(const T p)
0282 {
0283 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SINGULARITY_SERIES
0284 std::size_t saved_precision = std::cout.precision(3);
0285 std::cout << "Singularity_series Lambert_w p argument = " << p << std::endl;
0286 std::cout
0287
0288
0289
0290 << std::endl;
0291 std::cout.precision(saved_precision);
0292 #endif
0293
0294 static const T q[] =
0295 {
0296 -static_cast<T>(1),
0297 +T(1),
0298 -T(1) / 3,
0299 +T(11) / 72,
0300 -T(43) / 540,
0301 +T(769) / 17280,
0302 -T(221) / 8505,
0303
0304
0305 +T(680863uLL) / 43545600uLL,
0306
0307 -T(1963uLL) / 204120uLL,
0308
0309 +T(226287557uLL) / 37623398400uLL,
0310 -T(5776369uLL) / 1515591000uLL,
0311
0312 +T(169709463197uLL) / 69528040243200uLL,
0313
0314 -T(1118511313uLL) / 709296588000uLL,
0315 +T(667874164916771uLL) / 650782456676352000uLL,
0316
0317 -T(500525573uLL) / 744761417400uLL,
0318
0319
0320
0321 BOOST_MATH_BIG_CONSTANT(T, 64, +0.000442473061814620910),
0322
0323 BOOST_MATH_BIG_CONSTANT(T, 64, -0.000292677224729627445),
0324
0325 BOOST_MATH_BIG_CONSTANT(T, 64, 0.000194387276054539318),
0326
0327 BOOST_MATH_BIG_CONSTANT(T, 64, -0.000129574266852748819),
0328
0329 BOOST_MATH_BIG_CONSTANT(T, 64, +0.0000866503580520812717),
0330
0331
0332
0333
0334 BOOST_MATH_BIG_CONSTANT(T, 113, -0.000058113607504413816772205464778828177256611844221913)
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344 };
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381 BOOST_MATH_STD_USING
0382
0383 const T absp = abs(p);
0384
0385 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_TERMS
0386 {
0387 int terms = 20;
0388 if (absp < 0.01159)
0389 {
0390 terms = 6;
0391 }
0392 else if (absp < 0.0766)
0393 {
0394 terms = 10;
0395 }
0396 std::streamsize saved_precision = std::cout.precision(3);
0397 std::cout << "abs(p) = " << absp << ", terms = " << terms << std::endl;
0398 std::cout.precision(saved_precision);
0399 }
0400 #endif
0401
0402 if (absp < T(0.01159))
0403 {
0404 return
0405 -1 +
0406 p * (1 +
0407 p * (q[2] +
0408 p * (q[3] +
0409 p * (q[4] +
0410 p * (q[5] +
0411 p * q[6]
0412 )))));
0413 }
0414 else if (absp < T(0.0766))
0415 {
0416 return
0417 -1 +
0418 p * (1 +
0419 p * (q[2] +
0420 p * (q[3] +
0421 p * (q[4] +
0422 p * (q[5] +
0423 p * (q[6] +
0424 p * (q[7] +
0425 p * (q[8] +
0426 p * (q[9] +
0427 p * q[10]
0428 )))))))));
0429 }
0430
0431 return
0432 -1 +
0433 p * (1 +
0434 p * (q[2] +
0435 p * (q[3] +
0436 p * (q[4] +
0437 p * (q[5] +
0438 p * (q[6] +
0439 p * (q[7] +
0440 p * (q[8] +
0441 p * (q[9] +
0442 p * (q[10] +
0443 p * (q[11] +
0444 p * (q[12] +
0445 p * (q[13] +
0446 p * (q[14] +
0447 p * (q[15] +
0448 p * (q[16] +
0449 p * (q[17] +
0450 p * (q[18] +
0451 p * (q[19] +
0452 p * q[20]
0453 )))))))))))))))))));
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463 }
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519 template <typename T, typename Policy>
0520 T lambert_w0_small_z(T x, const Policy&, std::integral_constant<int, 0> const&);
0521
0522 template <typename T, typename Policy>
0523 T lambert_w0_small_z(T x, const Policy&, std::integral_constant<int, 1> const&);
0524
0525 template <typename T, typename Policy>
0526 T lambert_w0_small_z(T x, const Policy&, std::integral_constant<int, 2> const&);
0527
0528 template <typename T, typename Policy>
0529 T lambert_w0_small_z(T x, const Policy&, std::integral_constant<int, 3> const&);
0530
0531 template <typename T, typename Policy>
0532 T lambert_w0_small_z(T x, const Policy&, std::integral_constant<int, 4> const&);
0533
0534 template <typename T, typename Policy>
0535 T lambert_w0_small_z(T x, const Policy&, std::integral_constant<int, 5> const&);
0536
0537 template <typename T, typename Policy>
0538 T lambert_w0_small_z(T x, const Policy& pol)
0539 {
0540 using tag_type = std::integral_constant<int,
0541 std::numeric_limits<T>::is_specialized == 0 ? 5 :
0542 #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
0543 std::numeric_limits<T>::max_digits10 <= 9 ? 0 :
0544 std::numeric_limits<T>::max_digits10 <= 17 ? 1 :
0545 std::numeric_limits<T>::max_digits10 <= 22 ? 2 :
0546 std::numeric_limits<T>::max_digits10 < 37 ? 4
0547 #else
0548 std::numeric_limits<T>::radix != 2 ? 5 :
0549 std::numeric_limits<T>::digits <= 24 ? 0 :
0550 std::numeric_limits<T>::digits <= 53 ? 1 :
0551 std::numeric_limits<T>::digits <= 64 ? 2 :
0552 std::numeric_limits<T>::digits <= 113 ? 4
0553 #endif
0554 : 5>;
0555
0556 return lambert_w0_small_z(x, pol, tag_type());
0557 }
0558
0559
0560
0561
0562
0563
0564
0565 template <typename T, typename Policy>
0566 T lambert_w0_small_z(T z, const Policy&, std::integral_constant<int, 0> const&)
0567 {
0568 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0569 std::streamsize prec = std::cout.precision(std::numeric_limits<T>::max_digits10);
0570 std::cout << "\ntag_type 0 float lambert_w0_small_z called with z = " << z << " using " << 9 << " terms of precision "
0571 << std::numeric_limits<float>::max_digits10 << " decimal digits. " << std::endl;
0572 #endif
0573 T result =
0574 z * (1 -
0575 z * (1 -
0576 z * (static_cast<float>(3uLL) / 2uLL -
0577 z * (2.6666666666666666667F -
0578 z * (5.2083333333333333333F -
0579 z * (10.8F -
0580 z * (23.343055555555555556F -
0581 z * (52.012698412698412698F -
0582 z * 118.62522321428571429F))))))));
0583
0584 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0585 std::cout << "return w = " << result << std::endl;
0586 std::cout.precision(prec);
0587 #endif
0588
0589 return result;
0590 }
0591
0592
0593
0594
0595
0596
0597 template <typename T, typename Policy>
0598 T lambert_w0_small_z(const T z, const Policy&, std::integral_constant<int, 1> const&)
0599 {
0600 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0601 std::streamsize prec = std::cout.precision(std::numeric_limits<T>::max_digits10);
0602 std::cout << "\ntag_type 1 double lambert_w0_small_z called with z = " << z << " using " << 17 << " terms of precision, "
0603 << std::numeric_limits<double>::max_digits10 << " decimal digits. " << std::endl;
0604 #endif
0605 T result =
0606 z * (1. -
0607 z * (1. -
0608 z * (1.5 -
0609 z * (2.6666666666666666667 -
0610 z * (5.2083333333333333333 -
0611 z * (10.8 -
0612 z * (23.343055555555555556 -
0613 z * (52.012698412698412698 -
0614 z * (118.62522321428571429 -
0615 z * (275.57319223985890653 -
0616 z * (649.78717234347442681 -
0617 z * (1551.1605194805194805 -
0618 z * (3741.4497029592385495 -
0619 z * (9104.5002411580189358 -
0620 z * (22324.308512706601434 -
0621 z * (55103.621972903835338 -
0622 z * 136808.86090394293563))))))))))))))));
0623
0624 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0625 std::cout << "return w = " << result << std::endl;
0626 std::cout.precision(prec);
0627 #endif
0628
0629 return result;
0630 }
0631
0632
0633
0634
0635
0636
0637 template <typename T, typename Policy>
0638 T lambert_w0_small_z(const T z, const Policy&, std::integral_constant<int, 2> const&)
0639 {
0640 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0641 std::streamsize precision = std::cout.precision(std::numeric_limits<T>::max_digits10);
0642 std::cout << "\ntag_type 2 long double (80-bit double extended) lambert_w0_small_z called with z = " << z << " using " << 21 << " terms of precision, "
0643 << std::numeric_limits<long double>::max_digits10 << " decimal digits. " << std::endl;
0644 #endif
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669
0670 T result =
0671 z * (1.L -
0672 z * (1.L -
0673 z * (1.500000000000000000000000000000000L -
0674 z * (2.666666666666666666666666666666666L -
0675 z * (5.208333333333333333333333333333333L -
0676 z * (10.80000000000000000000000000000000L -
0677 z * (23.34305555555555555555555555555555L -
0678 z * (52.01269841269841269841269841269841L -
0679 z * (118.6252232142857142857142857142857L -
0680 z * (275.5731922398589065255731922398589L -
0681 z * (649.7871723434744268077601410934744L -
0682 z * (1551.160519480519480519480519480519L -
0683 z * (3741.449702959238549516327294105071L -
0684 z * (9104.500241158018935796713574491352L -
0685 z * (22324.308512706601434280005708577137L -
0686 z * (55103.621972903835337697771560205422L -
0687 z * (136808.86090394293563342215789305736L -
0688 z * (341422.05066583836331735491399356945L -
0689 z * (855992.9659966075514633630250633224L -
0690 z * (2.154990206091088289321708745358647e6L
0691 ))))))))))))))))))));
0692
0693 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0694 std::cout << "return w = " << result << std::endl;
0695 std::cout.precision(precision);
0696 #endif
0697 return result;
0698 }
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708 template <typename T, typename Policy>
0709 T lambert_w0_small_z(const T z, const Policy&, std::integral_constant<int, 3> const&)
0710 {
0711 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0712 std::streamsize precision = std::cout.precision(std::numeric_limits<T>::max_digits10);
0713 std::cout << "\ntag_type 3 long double (128-bit) lambert_w0_small_z called with z = " << z << " using " << 17 << " terms of precision, "
0714 << std::numeric_limits<double>::max_digits10 << " decimal digits. " << std::endl;
0715 #endif
0716 T result =
0717 z * (1.L -
0718 z * (1.L -
0719 z * (1.5L -
0720 z * (2.6666666666666666666666666666666666L -
0721 z * (5.2052083333333333333333333333333333L -
0722 z * (10.800000000000000000000000000000000L -
0723 z * (23.343055555555555555555555555555555L -
0724 z * (52.0126984126984126984126984126984126L -
0725 z * (118.625223214285714285714285714285714L -
0726 z * (275.57319223985890652557319223985890L -
0727 z * (649.78717234347442680776014109347442680776014109347L -
0728 z * (1551.1605194805194805194805194805194805194805194805L -
0729 z * (3741.4497029592385495163272941050718828496606274384L -
0730 z * (9104.5002411580189357967135744913522691300469078247L -
0731 z * (22324.308512706601434280005708577137148565719994291L -
0732 z * (55103.621972903835337697771560205422639285073147507L -
0733 z * 136808.86090394293563342215789305736395683485630576L
0734 ))))))))))))))));
0735
0736 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0737 std::cout << "return w = " << result << std::endl;
0738 std::cout.precision(precision);
0739 #endif
0740 return result;
0741 }
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753 #ifdef BOOST_HAS_FLOAT128
0754 template <typename T, typename Policy>
0755 T lambert_w0_small_z(const T z, const Policy&, std::integral_constant<int, 4> const&)
0756 {
0757 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0758 std::streamsize precision = std::cout.precision(std::numeric_limits<T>::max_digits10);
0759 std::cout << "\ntag_type 4 128-bit quad float128 lambert_w0_small_z called with z = " << z << " using " << 34 << " terms of precision, "
0760 << std::numeric_limits<float128>::max_digits10 << " max decimal digits." << std::endl;
0761 #endif
0762 T result =
0763 z * (1.Q -
0764 z * (1.Q -
0765 z * (1.500000000000000000000000000000000Q -
0766 z * (2.666666666666666666666666666666666Q -
0767 z * (5.208333333333333333333333333333333Q -
0768 z * (10.80000000000000000000000000000000Q -
0769 z * (23.34305555555555555555555555555555Q -
0770 z * (52.01269841269841269841269841269841Q -
0771 z * (118.6252232142857142857142857142857Q -
0772 z * (275.5731922398589065255731922398589Q -
0773 z * (649.7871723434744268077601410934744Q -
0774 z * (1551.160519480519480519480519480519Q -
0775 z * (3741.449702959238549516327294105071Q -
0776 z * (9104.500241158018935796713574491352Q -
0777 z * (22324.308512706601434280005708577137Q -
0778 z * (55103.621972903835337697771560205422Q -
0779 z * (136808.86090394293563342215789305736Q -
0780 z * (341422.05066583836331735491399356945Q -
0781 z * (855992.9659966075514633630250633224Q -
0782 z * (2.154990206091088289321708745358647e6Q -
0783 z * (5.445552922314462431642316420035073e6Q -
0784 z * (1.380733000216662949061923813184508e7Q -
0785 z * (3.511704498513923292853869855945334e7Q -
0786 z * (8.956800256102797693072819557780090e7Q -
0787 z * (2.290416846187949813964782641734774e8Q -
0788 z * (5.871035041171798492020292225245235e8Q -
0789 z * (1.508256053857792919641317138812957e9Q -
0790 z * (3.882630161293188940385873468413841e9Q -
0791 z * (1.001394313665482968013913601565723e10Q -
0792 z * (2.587356736265760638992878359024929e10Q -
0793 z * (6.696209709358073856946120522333454e10Q -
0794 z * (1.735711659599198077777078238043644e11Q -
0795 z * (4.505680465642353886756098108484670e11Q -
0796 z * (1.171223178256487391904047636564823e12Q
0797 ))))))))))))))))))))))))))))))))));
0798
0799
0800 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0801 std::cout << "return w = " << result << std::endl;
0802 std::cout.precision(precision);
0803 #endif
0804
0805 return result;
0806 }
0807
0808 #else
0809
0810 template <typename T, typename Policy>
0811 inline T lambert_w0_small_z(const T z, const Policy& pol, std::integral_constant<int, 4> const&)
0812 {
0813 return lambert_w0_small_z(z, pol, std::integral_constant<int, 5>());
0814 }
0815
0816 #endif
0817
0818
0819
0820 template <typename T>
0821 struct lambert_w0_small_z_series_term
0822 {
0823 using result_type = T;
0824
0825
0826
0827
0828
0829
0830 lambert_w0_small_z_series_term(T _z, T _term, int _k)
0831 : k(_k), z(_z), term(_term) { }
0832
0833 T operator()()
0834 {
0835 using std::pow;
0836 ++k;
0837 term *= -z / k;
0838
0839 T result = term * pow(T(k), T(-1 + k));
0840
0841 return result;
0842 }
0843 private:
0844 int k;
0845 T z;
0846 T term;
0847 };
0848
0849
0850 template <typename T, typename Policy>
0851 inline T lambert_w0_small_z(T z, const Policy& pol, std::integral_constant<int, 5> const&)
0852 {
0853 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0854 std::streamsize precision = std::cout.precision(std::numeric_limits<T>::max_digits10);
0855 std::cout << "Generic lambert_w0_small_z called with z = " << z << " using as many terms needed for precision." << std::endl;
0856 std::cout << "Argument z is of type " << typeid(T).name() << std::endl;
0857 #endif
0858
0859
0860
0861
0862
0863
0864
0865 static const T coeff[] =
0866 {
0867 0,
0868 1,
0869 -1,
0870 static_cast<T>(3uLL) / 2uLL,
0871 -static_cast<T>(8uLL) / 3uLL,
0872 static_cast<T>(125uLL) / 24uLL,
0873 -static_cast<T>(54uLL) / 5uLL,
0874 static_cast<T>(16807uLL) / 720uLL,
0875 -static_cast<T>(16384uLL) / 315uLL,
0876 static_cast<T>(531441uLL) / 4480uLL,
0877 -static_cast<T>(156250uLL) / 567uLL,
0878 static_cast<T>(2357947691uLL) / 3628800uLL,
0879 -static_cast<T>(2985984uLL) / 1925uLL,
0880 static_cast<T>(1792160394037uLL) / 479001600uLL,
0881 -static_cast<T>(7909306972uLL) / 868725uLL,
0882 static_cast<T>(320361328125uLL) / 14350336uLL,
0883 -static_cast<T>(35184372088832uLL) / 638512875uLL,
0884 static_cast<T>(2862423051509815793uLL) / 20922789888000uLL,
0885 -static_cast<T>(5083731656658uLL) / 14889875uLL,
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898
0899 };
0900
0901
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923
0924
0925
0926
0927 using boost::math::policies::get_epsilon;
0928 using boost::math::tools::sum_series;
0929 using boost::math::tools::evaluate_polynomial;
0930
0931
0932
0933
0934 T result = evaluate_polynomial(coeff, z);
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944
0945
0946
0947
0948
0949
0950
0951
0952
0953 lambert_w0_small_z_series_term<T> s(z, -pow<18>(z) / 6402373705728000uLL, 18);
0954
0955
0956
0957
0958
0959
0960
0961
0962
0963
0964 std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0965 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES
0966 std::cout << "max iter from policy = " << max_iter << std::endl;
0967
0968 #endif
0969
0970 result = sum_series(s, get_epsilon<T, Policy>(), max_iter, result);
0971
0972
0973
0974
0975
0976
0977
0978
0979
0980
0981 policies::check_series_iterations<T>("boost::math::lambert_w0_small_z<%1%>(%1%)", max_iter, pol);
0982 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_W_SMALL_Z_SERIES_ITERATIONS
0983 std::cout << "z = " << z << " needed " << max_iter << " iterations." << std::endl;
0984 std::cout.precision(prec);
0985 #endif
0986 return result;
0987 }
0988
0989
0990
0991 template <typename T>
0992 inline T lambert_w0_approx(T z)
0993 {
0994 BOOST_MATH_STD_USING
0995 T lz = log(z);
0996 T llz = log(lz);
0997 T w = lz - llz + (llz / lz);
0998 return w;
0999
1000 }
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016 template <typename T>
1017 inline T do_get_near_singularity_param(T z)
1018 {
1019 BOOST_MATH_STD_USING
1020 const T p2 = 2 * (boost::math::constants::e<T>() * z + 1);
1021 const T p = sqrt(p2);
1022 return p;
1023 }
1024 template <typename T, typename Policy>
1025 inline T get_near_singularity_param(T z, const Policy)
1026 {
1027 using value_type = typename policies::evaluation<T, Policy>::type;
1028 return static_cast<T>(do_get_near_singularity_param(static_cast<value_type>(z)));
1029 }
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041 template <typename T>
1042 T lambert_w_positive_rational_float(T z)
1043 {
1044 BOOST_MATH_STD_USING
1045 if (z < 2)
1046 {
1047 if (z < T(0.5))
1048 {
1049
1050
1051
1052 static const T Y = 8.196592331e-01f;
1053 static const T P[] = {
1054 1.803388345e-01f,
1055 -4.820256838e-01f,
1056 -1.068349741e+00f,
1057 -3.506624319e-02f,
1058 };
1059 static const T Q[] = {
1060 1.000000000e+00f,
1061 2.871703469e+00f,
1062 1.690949264e+00f,
1063 };
1064 return z * (Y + boost::math::tools::evaluate_polynomial(P, z) / boost::math::tools::evaluate_polynomial(Q, z));
1065 }
1066 else
1067 {
1068
1069 static const T Y = 5.503368378e-01f;
1070 static const T P[] = {
1071 4.493332766e-01f,
1072 2.543432707e-01f,
1073 -4.808788799e-01f,
1074 -1.244425316e-01f,
1075 };
1076 static const T Q[] = {
1077 1.000000000e+00f,
1078 2.780661241e+00f,
1079 1.830840318e+00f,
1080 2.407221031e-01f,
1081 };
1082 return z * (Y + boost::math::tools::evaluate_rational(P, Q, z));
1083 }
1084 }
1085 else if (z < 6)
1086 {
1087
1088
1089 static const T Y = 1.162393570e+00f;
1090 static const T P[] = {
1091 -1.144183394e+00f,
1092 -4.712732855e-01f,
1093 1.563162512e-01f,
1094 1.434010911e-02f,
1095 };
1096 static const T Q[] = {
1097 1.000000000e+00f,
1098 1.192626340e+00f,
1099 2.295580708e-01f,
1100 5.477869455e-03f,
1101 };
1102 return Y + boost::math::tools::evaluate_rational(P, Q, z);
1103 }
1104 else if (z < 18)
1105 {
1106
1107
1108 static const T Y = 1.809371948e+00f;
1109 static const T P[] = {
1110 -1.689291769e+00f,
1111 -3.337812742e-01f,
1112 3.151434873e-02f,
1113 1.134178734e-03f,
1114 };
1115 static const T Q[] = {
1116 1.000000000e+00f,
1117 5.716915685e-01f,
1118 4.489521292e-02f,
1119 4.076716763e-04f,
1120 };
1121 return Y + boost::math::tools::evaluate_rational(P, Q, z);
1122 }
1123 else if (z < T(9897.12905874))
1124 {
1125
1126 static const T Y = -1.402973175e+00f;
1127 static const T P[] = {
1128 1.966174312e+00f,
1129 2.350864728e-01f,
1130 -5.098074353e-02f,
1131 -1.054818339e-02f,
1132 };
1133 static const T Q[] = {
1134 1.000000000e+00f,
1135 4.388208264e-01f,
1136 8.316639634e-02f,
1137 3.397187918e-03f,
1138 -1.321489743e-05f,
1139 };
1140 T log_w = log(z);
1141 return log_w + Y + boost::math::tools::evaluate_polynomial(P, log_w) / boost::math::tools::evaluate_polynomial(Q, log_w);
1142 }
1143 else if (z < T(7.896296e+13))
1144 {
1145
1146 static const T Y = -2.735729218e+00f;
1147 static const T P[] = {
1148 3.424903470e+00f,
1149 7.525631787e-02f,
1150 -1.427309584e-02f,
1151 -1.435974178e-05f,
1152 };
1153 static const T Q[] = {
1154 1.000000000e+00f,
1155 2.514005579e-01f,
1156 6.118994652e-03f,
1157 -1.357889535e-05f,
1158 7.312865624e-08f,
1159 };
1160 T log_w = log(z);
1161 return log_w + Y + boost::math::tools::evaluate_polynomial(P, log_w) / boost::math::tools::evaluate_polynomial(Q, log_w);
1162 }
1163
1164
1165 static const T Y = -4.012863159e+00f;
1166 static const T P[] = {
1167 4.431629226e+00f,
1168 2.756690487e-01f,
1169 -2.992956930e-03f,
1170 -4.912259384e-05f,
1171 };
1172 static const T Q[] = {
1173 1.000000000e+00f,
1174 2.015434591e-01f,
1175 4.949426142e-03f,
1176 1.609659944e-05f,
1177 -5.111523436e-09f,
1178 };
1179 T log_w = log(z);
1180 return log_w + Y + boost::math::tools::evaluate_polynomial(P, log_w) / boost::math::tools::evaluate_polynomial(Q, log_w);
1181
1182 }
1183
1184 template <typename T, typename Policy>
1185 T lambert_w_negative_rational_float(T z, const Policy& pol)
1186 {
1187 BOOST_MATH_STD_USING
1188 if (z > T(-0.27))
1189 {
1190 if (z < T(-0.051))
1191 {
1192
1193
1194 static const T Y = 1.255809784e+00f;
1195 static const T P[] = {
1196 -2.558083412e-01f,
1197 -2.306524098e+00f,
1198 -5.630887033e+00f,
1199 -3.803974556e+00f,
1200 };
1201 static const T Q[] = {
1202 1.000000000e+00f,
1203 5.107680783e+00f,
1204 7.914062868e+00f,
1205 3.501498501e+00f,
1206 };
1207 return z * (Y + boost::math::tools::evaluate_rational(P, Q, z));
1208 }
1209 else
1210 {
1211
1212 return lambert_w0_small_z(z, pol);
1213 }
1214 }
1215 else if (z > T(-0.3578794411714423215955237701))
1216 {
1217
1218 static const T Y = 1.220928431e-01f;
1219 static const T P[] = {
1220 -1.221787446e-01f,
1221 -6.816155875e+00f,
1222 7.144582035e+01f,
1223 1.128444390e+03f,
1224 };
1225 static const T Q[] = {
1226 1.000000000e+00f,
1227 6.480326790e+01f,
1228 1.869145243e+02f,
1229 -1.361804274e+03f,
1230 1.117826726e+03f,
1231 };
1232 T d = z + 0.367879441171442321595523770161460867445811f;
1233 return -d / (Y + boost::math::tools::evaluate_polynomial(P, d) / boost::math::tools::evaluate_polynomial(Q, d));
1234 }
1235
1236 return lambert_w_singularity_series(get_near_singularity_param(z, pol));
1237 }
1238
1239
1240 template <typename T, typename Policy>
1241 inline T lambert_w0_imp(T z, const Policy& pol, const std::integral_constant<int, 1>&)
1242 {
1243 static const char* function = "boost::math::lambert_w0<%1%>";
1244 BOOST_MATH_STD_USING
1245
1246 if ((boost::math::isnan)(z))
1247 {
1248 return boost::math::policies::raise_domain_error<T>(function, "Expected a value > -e^-1 (-0.367879...) but got %1%.", z, pol);
1249 }
1250 if ((boost::math::isinf)(z))
1251 {
1252 return boost::math::policies::raise_overflow_error<T>(function, "Expected a finite value but got %1%.", z, pol);
1253 }
1254
1255 if (z >= T(0.05))
1256
1257 {
1258 return lambert_w_positive_rational_float(z);
1259 }
1260 else if (z <= -0.3678794411714423215955237701614608674458111310f)
1261 {
1262 if (z < -0.3678794411714423215955237701614608674458111310f)
1263 return boost::math::policies::raise_domain_error<T>(function, "Expected z >= -e^-1 (-0.367879...) but got %1%.", z, pol);
1264 return -1;
1265 }
1266
1267 return lambert_w_negative_rational_float(z, pol);
1268 }
1269
1270 template <typename T>
1271 T lambert_w_positive_rational_double(T z)
1272 {
1273 BOOST_MATH_STD_USING
1274 if (z < 2)
1275 {
1276 if (z < 0.5)
1277 {
1278
1279 static const T offset = 8.19659233093261719e-01;
1280 static const T P[] = {
1281 1.80340766906685177e-01,
1282 3.28178241493119307e-01,
1283 -2.19153620687139706e+00,
1284 -7.24750929074563990e+00,
1285 -7.28395876262524204e+00,
1286 -2.57417169492512916e+00,
1287 -2.31606948888704503e-01
1288 };
1289 static const T Q[] = {
1290 1.00000000000000000e+00,
1291 7.36482529307436604e+00,
1292 2.03686007856430677e+01,
1293 2.62864592096657307e+01,
1294 1.59742041380858333e+01,
1295 4.03760534788374589e+00,
1296 2.91327346750475362e-01
1297 };
1298 return z * (offset + boost::math::tools::evaluate_polynomial(P, z) / boost::math::tools::evaluate_polynomial(Q, z));
1299 }
1300 else
1301 {
1302
1303 static const T offset = 5.50335884094238281e-01;
1304 static const T P[] = {
1305 4.49664083944098322e-01,
1306 1.90417666196776909e+00,
1307 1.99951368798255994e+00,
1308 -6.91217310299270265e-01,
1309 -1.88533935998617058e+00,
1310 -7.96743968047750836e-01,
1311 -1.02891726031055254e-01,
1312 -3.09156013592636568e-03
1313 };
1314 static const T Q[] = {
1315 1.00000000000000000e+00,
1316 6.45854489419584014e+00,
1317 1.54739232422116048e+01,
1318 1.72606164253337843e+01,
1319 9.29427055609544096e+00,
1320 2.29040824649748117e+00,
1321 2.21610620995418981e-01,
1322 5.70597669908194213e-03
1323 };
1324 return z * (offset + boost::math::tools::evaluate_rational(P, Q, z));
1325 }
1326 }
1327 else if (z < 6)
1328 {
1329
1330
1331 static const T Y = 1.16239356994628906e+00;
1332 static const T P[] = {
1333 -1.16230494982099475e+00,
1334 -3.38528144432561136e+00,
1335 -2.55653717293161565e+00,
1336 -3.06755172989214189e-01,
1337 1.73149743765268289e-01,
1338 3.76906042860014206e-02,
1339 1.84552217624706666e-03,
1340 1.69434126904822116e-05,
1341 };
1342 static const T Q[] = {
1343 1.00000000000000000e+00,
1344 3.77187616711220819e+00,
1345 4.58799960260143701e+00,
1346 2.24101228462292447e+00,
1347 4.54794195426212385e-01,
1348 3.60761772095963982e-02,
1349 9.25176499518388571e-04,
1350 4.43611344705509378e-06,
1351 };
1352 return Y + boost::math::tools::evaluate_rational(P, Q, z);
1353 }
1354 else if (z < 18)
1355 {
1356
1357
1358 static const T offset = 1.80937194824218750e+00;
1359 static const T P[] =
1360 {
1361 -1.80690935424793635e+00,
1362 -3.66995929380314602e+00,
1363 -1.93842957940149781e+00,
1364 -2.94269984375794040e-01,
1365 1.81224710627677778e-03,
1366 2.48166798603547447e-03,
1367 1.15806592415397245e-04,
1368 1.43105573216815533e-06,
1369 3.47281483428369604e-09
1370 };
1371 static const T Q[] = {
1372 1.00000000000000000e+00,
1373 2.57319080723908597e+00,
1374 1.96724528442680658e+00,
1375 5.84501352882650722e-01,
1376 7.37152837939206240e-02,
1377 3.97368430940416778e-03,
1378 8.54941838187085088e-05,
1379 6.05713225608426678e-07,
1380 8.17517283816615732e-10
1381 };
1382 return offset + boost::math::tools::evaluate_rational(P, Q, z);
1383 }
1384 else if (z < 9897.12905874)
1385 {
1386
1387 static const T Y = -1.40297317504882812e+00;
1388 static const T P[] = {
1389 1.97011826279311924e+00,
1390 1.05639945701546704e+00,
1391 3.33434529073196304e-01,
1392 3.34619153200386816e-02,
1393 -5.36238353781326675e-03,
1394 -2.43901294871308604e-03,
1395 -2.13762095619085404e-04,
1396 -4.85531936495542274e-06,
1397 -2.02473518491905386e-08,
1398 };
1399 static const T Q[] = {
1400 1.00000000000000000e+00,
1401 8.60107275833921618e-01,
1402 4.10420467985504373e-01,
1403 1.18444884081994841e-01,
1404 2.16966505556021046e-02,
1405 2.24529766630769097e-03,
1406 9.82045090226437614e-05,
1407 1.36363515125489502e-06,
1408 3.44200749053237945e-09,
1409 };
1410 T log_w = log(z);
1411 return log_w + Y + boost::math::tools::evaluate_rational(P, Q, log_w);
1412 }
1413 else if (z < 7.896296e+13)
1414 {
1415
1416 static const T Y = -2.73572921752929688e+00;
1417 static const T P[] = {
1418 3.30547638424076217e+00,
1419 1.64050071277550167e+00,
1420 4.57149576470736039e-01,
1421 4.03821227745424840e-02,
1422 -4.99664976882514362e-04,
1423 -1.28527893803052956e-04,
1424 -2.95470325373338738e-06,
1425 -1.76662025550202762e-08,
1426 -1.98721972463709290e-11,
1427 };
1428 static const T Q[] = {
1429 1.00000000000000000e+00,
1430 6.91472559412458759e-01,
1431 2.48154578891676774e-01,
1432 4.60893578284335263e-02,
1433 3.60207838982301946e-03,
1434 1.13001153242430471e-04,
1435 1.33690948263488455e-06,
1436 4.97253225968548872e-09,
1437 3.39460723731970550e-12,
1438 };
1439 T log_w = log(z);
1440 return log_w + Y + boost::math::tools::evaluate_rational(P, Q, log_w);
1441 }
1442 else if (z < 2.6881171e+43)
1443 {
1444
1445 static const T Y = -4.01286315917968750e+00;
1446 static const T P[] = {
1447 5.07714858354309672e+00,
1448 -3.32994414518701458e+00,
1449 -8.61170416909864451e-01,
1450 -4.01139705309486142e-02,
1451 -1.85374201771834585e-04,
1452 1.08824145844270666e-05,
1453 1.17216905810452396e-07,
1454 2.97998248101385990e-10,
1455 1.42294856434176682e-13,
1456 };
1457 static const T Q[] = {
1458 1.00000000000000000e+00,
1459 -4.85840770639861485e-01,
1460 -3.18714850604827580e-01,
1461 -3.20966129264610534e-02,
1462 -1.06276178044267895e-03,
1463 -1.33597828642644955e-05,
1464 -6.27900905346219472e-08,
1465 -9.35271498075378319e-11,
1466 -2.60648331090076845e-14,
1467 };
1468 T log_w = log(z);
1469 return log_w + Y + boost::math::tools::evaluate_rational(P, Q, log_w);
1470 }
1471 else
1472 {
1473
1474 static const T Y = -5.70115661621093750e+00;
1475 static const T P[] = {
1476 6.42275660145116698e+00,
1477 1.33047964073367945e+00,
1478 6.72008923401652816e-02,
1479 1.16444069958125895e-03,
1480 7.06966760237470501e-06,
1481 5.48974896149039165e-09,
1482 -7.00379652018853621e-11,
1483 -1.89247635913659556e-13,
1484 -1.55898770790170598e-16,
1485 -4.06109208815303157e-20,
1486 -2.21552699006496737e-24,
1487 };
1488 static const T Q[] = {
1489 1.00000000000000000e+00,
1490 3.34498588416632854e-01,
1491 2.51519862456384983e-02,
1492 6.81223810622416254e-04,
1493 7.94450897106903537e-06,
1494 4.30675039872881342e-08,
1495 1.10667669458467617e-10,
1496 1.31012240694192289e-13,
1497 6.53282047177727125e-17,
1498 1.11775518708172009e-20,
1499 3.78250395617836059e-25,
1500 };
1501 T log_w = log(z);
1502 return log_w + Y + boost::math::tools::evaluate_rational(P, Q, log_w);
1503 }
1504 }
1505
1506 template <typename T, typename Policy>
1507 T lambert_w_negative_rational_double(T z, const Policy& pol)
1508 {
1509 BOOST_MATH_STD_USING
1510 if (z > -0.1)
1511 {
1512 if (z < -0.051)
1513 {
1514
1515
1516
1517
1518 static const T Y = 1.08633995056152344e+00;
1519 static const T P[] = {
1520 -8.63399505615014331e-02,
1521 -1.64303871814816464e+00,
1522 -7.71247913918273738e+00,
1523 -1.41014495545382454e+01,
1524 -1.02269079949257616e+01,
1525 -2.17236002836306691e+00,
1526 };
1527 static const T Q[] = {
1528 1.00000000000000000e+00,
1529 7.44775406945739243e+00,
1530 2.04392643087266541e+01,
1531 2.51001961077774193e+01,
1532 1.31256080849023319e+01,
1533 2.11640324843601588e+00,
1534 };
1535 return z * (Y + boost::math::tools::evaluate_rational(P, Q, z));
1536 }
1537 else
1538 {
1539
1540 return lambert_w0_small_z(z, pol);
1541 }
1542 }
1543 else if (z > -0.2)
1544 {
1545
1546
1547
1548
1549 static const T Y = 1.20359611511230469e+00;
1550 static const T P[] = {
1551 -2.03596115108465635e-01,
1552 -2.95029082937201859e+00,
1553 -1.54287922188671648e+01,
1554 -3.81185809571116965e+01,
1555 -4.66384358235575985e+01,
1556 -2.59282069989642468e+01,
1557 -4.70140451266553279e+00,
1558 };
1559 static const T Q[] = {
1560 1.00000000000000000e+00,
1561 9.57921436074599929e+00,
1562 3.60988119290234377e+01,
1563 6.73977699505546007e+01,
1564 6.41104992068148823e+01,
1565 2.82060127225153607e+01,
1566 4.10677610657724330e+00,
1567 };
1568 return z * (Y + boost::math::tools::evaluate_rational(P, Q, z));
1569 }
1570 else if (z > -0.3178794411714423215955237)
1571 {
1572
1573 static const T Y = 3.49680423736572266e-01;
1574 static const T P[] = {
1575 -3.49729841718749014e-01,
1576 -6.28207407760709028e+01,
1577 -2.57226178029669171e+03,
1578 -2.50271008623093747e+04,
1579 1.11949239154711388e+05,
1580 1.85684566607844318e+06,
1581 4.80802490427638643e+06,
1582 2.76624752134636406e+06,
1583 };
1584 static const T Q[] = {
1585 1.00000000000000000e+00,
1586 1.82717661215113000e+02,
1587 8.00121119810280100e+03,
1588 1.06073266717010129e+05,
1589 3.22848993926057721e+05,
1590 -8.05684814514171256e+05,
1591 -2.59223192927265737e+06,
1592 -5.61719645211570871e+05,
1593 6.27765369292636844e+04,
1594 };
1595 T d = z + 0.367879441171442321595523770161460867445811;
1596 return -d / (Y + boost::math::tools::evaluate_polynomial(P, d) / boost::math::tools::evaluate_polynomial(Q, d));
1597 }
1598 else if (z > -0.3578794411714423215955237701)
1599 {
1600
1601 static const T Y = 5.00126481056213379e-02;
1602 static const T P[] = {
1603 -5.00173570682372162e-02,
1604 -4.44242461870072044e+01,
1605 -9.51185533619946042e+03,
1606 -5.88605699015429386e+05,
1607 -1.90760843597427751e+06,
1608 5.79797663818311404e+08,
1609 1.11383352508459134e+10,
1610 5.67791253678716467e+10,
1611 6.32694500716584572e+10,
1612 };
1613 static const T Q[] = {
1614 1.00000000000000000e+00,
1615 9.08910517489981551e+02,
1616 2.10170163753340133e+05,
1617 1.67858612416470327e+07,
1618 4.90435561733227953e+08,
1619 4.54978142622939917e+09,
1620 2.87716585708739168e+09,
1621 -4.59414247951143131e+10,
1622 -1.72845216404874299e+10,
1623 };
1624 T d = z + 0.36787944117144232159552377016146086744581113103176804;
1625 return -d / (Y + boost::math::tools::evaluate_polynomial(P, d) / boost::math::tools::evaluate_polynomial(Q, d));
1626 }
1627 else
1628 {
1629
1630 const T p2 = 2 * (boost::math::constants::e<T>() * z + 1);
1631 const T p = sqrt(p2);
1632 return lambert_w_detail::lambert_w_singularity_series(p);
1633 }
1634 }
1635
1636
1637 template <typename T, typename Policy>
1638 inline T lambert_w0_imp(T z, const Policy& pol, const std::integral_constant<int, 2>&)
1639 {
1640 static const char* function = "boost::math::lambert_w0<%1%>";
1641 BOOST_MATH_STD_USING
1642
1643
1644 static_assert(std::numeric_limits<double>::digits >= 53,
1645 "Our double precision coefficients will be truncated, "
1646 "please file a bug report with details of your platform's floating point types "
1647 "- or possibly edit the coefficients to have "
1648 "an appropriate size-suffix for 64-bit floats on your platform - L?");
1649
1650 if ((boost::math::isnan)(z))
1651 {
1652 return boost::math::policies::raise_domain_error<T>(function, "Expected a value > -e^-1 (-0.367879...) but got %1%.", z, pol);
1653 }
1654 if ((boost::math::isinf)(z))
1655 {
1656 return boost::math::policies::raise_overflow_error<T>(function, "Expected a finite value but got %1%.", z, pol);
1657 }
1658
1659 if (z >= 0.05)
1660 {
1661 return lambert_w_positive_rational_double(z);
1662 }
1663 else if (z <= -0.36787944117144232159552377016146086744581113103176804)
1664 {
1665 if (z < -0.36787944117144232159552377016146086744581113103176804)
1666 {
1667 return boost::math::policies::raise_domain_error<T>(function, "Expected z >= -e^-1 (-0.367879...) but got %1%.", z, pol);
1668 }
1669 return -1;
1670 }
1671 else
1672 {
1673 return lambert_w_negative_rational_double(z, pol);
1674 }
1675 }
1676
1677
1678
1679
1680
1681 template <typename T, typename Policy>
1682 inline T lambert_w0_imp(T z, const Policy& pol, const std::integral_constant<int, 0>&)
1683 {
1684 static const char* function = "boost::math::lambert_w0<%1%>";
1685 BOOST_MATH_STD_USING
1686
1687
1688 if ((boost::math::isnan)(z))
1689 {
1690 return boost::math::policies::raise_domain_error<T>(function, "Expected z >= -e^-1 (-0.367879...) but got %1%.", z, pol);
1691 }
1692 if (fabs(z) <= 0.05f)
1693 {
1694
1695 return lambert_w0_small_z(z, pol);
1696 }
1697 if (z > (std::numeric_limits<double>::max)())
1698 {
1699 if ((boost::math::isinf)(z))
1700 {
1701 return policies::raise_overflow_error<T>(function, nullptr, pol);
1702
1703
1704 }
1705
1706
1707
1708 T w = lambert_w0_approx(z);
1709
1710
1711
1712 return lambert_w_halley_iterate(w, z);
1713 }
1714 if (z < -0.3578794411714423215955237701)
1715 {
1716 if (z <= -boost::math::constants::exp_minus_one<T>())
1717 {
1718 if (z == -boost::math::constants::exp_minus_one<T>())
1719 {
1720 return -1;
1721 }
1722 return boost::math::policies::raise_domain_error<T>(function, "Expected z >= -e^-1 (-0.367879...) but got %1%.", z, pol);
1723 }
1724
1725
1726 const T p2 = 2 * (boost::math::constants::e<T>() * z + 1);
1727 const T p = sqrt(p2);
1728 T w = lambert_w_detail::lambert_w_singularity_series(p);
1729 return lambert_w_halley_iterate(w, z);
1730 }
1731
1732
1733
1734
1735
1736
1737
1738 using precision_type = typename policies::precision<T, Policy>::type;
1739 using tag_type = std::integral_constant<bool,
1740 (precision_type::value == 0) || (precision_type::value > 113) ?
1741 true
1742 : false
1743 >;
1744
1745
1746
1747 T w = lambert_w0_imp(maybe_reduce_to_double(z, std::is_constructible<double, T>()), pol, std::integral_constant<int, 2>());
1748
1749 return lambert_w_maybe_halley_iterate(w, z, tag_type());
1750
1751 }
1752
1753
1754
1755
1756
1757
1758 template<typename T, typename Policy>
1759 T lambert_wm1_imp(const T z, const Policy& pol)
1760 {
1761
1762
1763
1764
1765
1766
1767
1768 static_assert(!std::is_integral<T>::value,
1769 "Must be floating-point or fixed type (not integer type), for example: lambert_wm1(1.), not lambert_wm1(1)!");
1770
1771 BOOST_MATH_STD_USING
1772
1773 const char* function = "boost::math::lambert_wm1<RealType>(<RealType>)";
1774
1775
1776 if ((boost::math::isnan)(z))
1777 {
1778 return policies::raise_domain_error(function,
1779 "Argument z is NaN!",
1780 z, pol);
1781 }
1782
1783 if ((boost::math::isinf)(z))
1784 {
1785 return policies::raise_domain_error(function,
1786 "Argument z is infinite!",
1787 z, pol);
1788 }
1789
1790 if (z == static_cast<T>(0))
1791 {
1792 if (std::numeric_limits<T>::has_infinity)
1793 {
1794 return -std::numeric_limits<T>::infinity();
1795 }
1796 else
1797 {
1798 return -tools::max_value<T>();
1799 }
1800 }
1801 if (boost::math::detail::has_denorm_now<T>())
1802 {
1803 if (!(boost::math::isnormal)(z))
1804 {
1805 return policies::raise_overflow_error(function,
1806 "Argument z = %1% is denormalized! (must be z > (std::numeric_limits<RealType>::min)() or z == 0)",
1807 z, pol);
1808 }
1809 }
1810
1811 if (z > static_cast<T>(0))
1812 {
1813 return policies::raise_domain_error(function,
1814 "Argument z = %1% is out of range (z <= 0) for Lambert W-1 branch! (Try Lambert W0 branch?)",
1815 z, pol);
1816 }
1817 if (z > -boost::math::tools::min_value<T>())
1818 {
1819
1820
1821 return policies::raise_overflow_error(function,
1822 "Argument z = %1% is too small (z < -std::numeric_limits<T>::min so denormalized) for Lambert W-1 branch!",
1823 z, pol);
1824 }
1825 if (z == -boost::math::constants::exp_minus_one<T>())
1826 {
1827 return -static_cast<T>(1);
1828 }
1829
1830 if (z < -boost::math::constants::exp_minus_one<T>())
1831 {
1832 return policies::raise_domain_error(function,
1833 "Argument z = %1% is out of range (z < -exp(-1) = -3.6787944... <= 0) for Lambert W-1 (or W0) branch!",
1834 z, pol);
1835 }
1836 if (z < static_cast<T>(-0.35))
1837 {
1838 const T p2 = 2 * (boost::math::constants::e<T>() * z + 1);
1839 if (p2 == 0)
1840 {
1841 return -1;
1842 }
1843 if (p2 > 0)
1844 {
1845 T w_series = lambert_w_singularity_series(T(-sqrt(p2)));
1846 if (boost::math::tools::digits<T>() > 53)
1847 {
1848 w_series = lambert_w_detail::lambert_w_halley_iterate(w_series, z);
1849 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_WM1_NOT_BUILTIN
1850 std::streamsize saved_precision = std::cout.precision(std::numeric_limits<T>::max_digits10);
1851 std::cout << "Lambert W-1 Halley updated to " << w_series << std::endl;
1852 std::cout.precision(saved_precision);
1853 #endif
1854 }
1855 return w_series;
1856 }
1857
1858 return policies::raise_domain_error(function,
1859 "Argument z = %1% is out of range for Lambert W-1 branch. (Should not get here - please report!)",
1860 z, pol);
1861 }
1862
1863 using lambert_w_lookup::wm1es;
1864 using lambert_w_lookup::wm1zs;
1865 using lambert_w_lookup::noof_wm1zs;
1866
1867
1868
1869
1870
1871 if (z >= T(wm1zs[63]))
1872 {
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893 T guess;
1894 T lz = log(-z);
1895 T llz = log(-lz);
1896 guess = lz - llz + (llz / lz);
1897 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_WM1_TINY
1898 std::streamsize saved_precision = std::cout.precision(std::numeric_limits<T>::max_digits10);
1899 std::cout << "z = " << z << ", guess = " << guess << ", ln(-z) = " << lz << ", ln(-ln(-z) = " << llz << ", llz/lz = " << (llz / lz) << std::endl;
1900
1901
1902
1903 int d10 = policies::digits_base10<T, Policy>();
1904 int d2 = policies::digits<T, Policy>();
1905 std::cout << "digits10 = " << d10 << ", digits2 = " << d2
1906 << std::endl;
1907 std::cout.precision(saved_precision);
1908 #endif
1909 if (policies::digits<T, Policy>() < 12)
1910 {
1911 return guess;
1912 }
1913 T result = lambert_w_detail::lambert_w_halley_iterate(guess, z);
1914 return result;
1915
1916
1917
1918
1919
1920
1921 }
1922
1923
1924 if (boost::math::tools::digits<T>() > 53)
1925 {
1926
1927
1928
1929 using boost::math::policies::precision;
1930 using boost::math::policies::digits10;
1931 using boost::math::policies::digits2;
1932 using boost::math::policies::policy;
1933
1934 T double_approx(static_cast<T>(lambert_wm1_imp(must_reduce_to_double(z, std::is_constructible<double, T>()), policy<digits2<50>>())));
1935 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_WM1_NOT_BUILTIN
1936 std::streamsize saved_precision = std::cout.precision(std::numeric_limits<T>::max_digits10);
1937 std::cout << "Lambert_wm1 Argument Type " << typeid(T).name() << " approximation double = " << double_approx << std::endl;
1938 std::cout.precision(saved_precision);
1939 #endif
1940
1941
1942 T result = lambert_w_halley_iterate(double_approx, z);
1943 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_WM1
1944 std::streamsize saved_precision = std::cout.precision(std::numeric_limits<T>::max_digits10);
1945 std::cout << "Result " << typeid(T).name() << " precision Halley refinement = " << result << std::endl;
1946 std::cout.precision(saved_precision);
1947 #endif
1948 return result;
1949 }
1950 else
1951 {
1952 using namespace boost::math::lambert_w_detail::lambert_w_lookup;
1953
1954
1955 int n = 2;
1956 if (T(wm1zs[n - 1]) > z)
1957 {
1958 goto bisect;
1959 }
1960 for (int j = 1; j <= 5; ++j)
1961 {
1962 n *= 2;
1963 if (T(wm1zs[n - 1]) > z)
1964 {
1965 goto overshot;
1966 }
1967 }
1968
1969
1970 return policies::raise_domain_error(function,
1971 "Argument z = %1% is too small (< -1.026439e-26) (logic error - please report!)",
1972 z, pol);
1973 overshot:
1974 {
1975 int nh = n / 2;
1976 for (int j = 1; j <= 5; ++j)
1977 {
1978 nh /= 2;
1979 if (nh <= 0)
1980 {
1981 break;
1982 }
1983 if (T(wm1zs[n - nh - 1]) > z)
1984 {
1985 n -= nh;
1986 }
1987 }
1988 }
1989 bisect:
1990 --n;
1991
1992
1993 #ifdef BOOST_MATH_INSTRUMENT_LAMBERT_WM1_LOOKUP
1994 std::streamsize saved_precision = std::cout.precision(std::numeric_limits<T>::max_digits10);
1995 std::cout << "Result lookup W-1(" << z << ") bisection between wm1zs[" << n - 1 << "] = " << wm1zs[n - 1] << " and wm1zs[" << n << "] = " << wm1zs[n]
1996 << ", bisect mean = " << (wm1zs[n - 1] + wm1zs[n]) / 2 << std::endl;
1997 std::cout.precision(saved_precision);
1998 #endif
1999
2000
2001
2002
2003
2004 int bisections = 11;
2005 if (n >= 8)
2006 {
2007 bisections = 8;
2008 }
2009 else if (n >= 3)
2010 {
2011 bisections = 9;
2012 }
2013 else if (n >= 2)
2014 {
2015 bisections = 10;
2016 }
2017
2018
2019
2020
2021 using lambert_w_lookup::halves;
2022 using lambert_w_lookup::sqrtwm1s;
2023
2024 using calc_type = typename std::conditional<std::is_constructible<lookup_t, T>::value, lookup_t, T>::type;
2025
2026 calc_type w = -static_cast<calc_type>(n);
2027 calc_type y = static_cast<calc_type>(z * T(wm1es[n - 1]));
2028
2029 for (int j = 0; j < bisections; ++j)
2030 {
2031 calc_type wj = w - halves[j];
2032 calc_type yj = y * sqrtwm1s[j];
2033 if (wj < yj)
2034 {
2035 w = wj;
2036 y = yj;
2037 }
2038 }
2039 return static_cast<T>(schroeder_update(w, y));
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053 }
2054 }
2055 }
2056
2057
2058
2059
2060 template <typename T, typename Policy>
2061 inline
2062 typename boost::math::tools::promote_args<T>::type
2063 lambert_w0(T z, const Policy& pol)
2064 {
2065
2066
2067 using result_type = typename tools::promote_args<T>::type;
2068
2069
2070
2071 using precision_type = typename policies::precision<result_type, Policy>::type;
2072
2073 using tag_type = std::integral_constant<int,
2074 (precision_type::value == 0) || (precision_type::value > 53) ?
2075 0
2076 : (precision_type::value <= 24) ? 1
2077 : 2
2078 >;
2079
2080 return lambert_w_detail::lambert_w0_imp(result_type(z), pol, tag_type());
2081 }
2082
2083
2084 template <typename T>
2085 inline
2086 typename tools::promote_args<T>::type
2087 lambert_w0(T z)
2088 {
2089
2090
2091 using result_type = typename tools::promote_args<T>::type;
2092
2093
2094
2095 using precision_type = typename policies::precision<result_type, policies::policy<>>::type;
2096
2097 using tag_type = std::integral_constant<int,
2098 (precision_type::value == 0) || (precision_type::value > 53) ?
2099 0
2100 : (precision_type::value <= 24) ? 1
2101 : 2
2102 >;
2103 return lambert_w_detail::lambert_w0_imp(result_type(z), policies::policy<>(), tag_type());
2104 }
2105
2106
2107
2108
2109 template <typename T, typename Policy>
2110 inline
2111 typename tools::promote_args<T>::type
2112 lambert_wm1(T z, const Policy& pol)
2113 {
2114
2115
2116 using result_type = typename tools::promote_args<T>::type;
2117 return lambert_w_detail::lambert_wm1_imp(result_type(z), pol);
2118 }
2119
2120
2121 template <typename T>
2122 inline
2123 typename tools::promote_args<T>::type
2124 lambert_wm1(T z)
2125 {
2126 using result_type = typename tools::promote_args<T>::type;
2127 return lambert_w_detail::lambert_wm1_imp(result_type(z), policies::policy<>());
2128 }
2129
2130
2131 template <typename T, typename Policy>
2132 inline typename tools::promote_args<T>::type
2133 lambert_w0_prime(T z, const Policy& pol)
2134 {
2135 using result_type = typename tools::promote_args<T>::type;
2136 using std::numeric_limits;
2137 if (z == 0)
2138 {
2139 return static_cast<result_type>(1);
2140 }
2141
2142
2143 if (z == - boost::math::constants::exp_minus_one<result_type>())
2144 {
2145 return numeric_limits<result_type>::has_infinity ? numeric_limits<result_type>::infinity() : boost::math::tools::max_value<result_type>();
2146 }
2147
2148 result_type w = lambert_w0(result_type(z), pol);
2149
2150
2151
2152
2153
2154
2155
2156 return w / (z * (1 + w));
2157 }
2158
2159 template <typename T>
2160 inline typename tools::promote_args<T>::type
2161 lambert_w0_prime(T z)
2162 {
2163 return lambert_w0_prime(z, policies::policy<>());
2164 }
2165
2166 template <typename T, typename Policy>
2167 inline typename tools::promote_args<T>::type
2168 lambert_wm1_prime(T z, const Policy& pol)
2169 {
2170 using std::numeric_limits;
2171 using result_type = typename tools::promote_args<T>::type;
2172
2173
2174
2175
2176
2177 if (z == 0 || z == - boost::math::constants::exp_minus_one<result_type>())
2178 {
2179 return numeric_limits<result_type>::has_infinity ? -numeric_limits<result_type>::infinity() : -boost::math::tools::max_value<result_type>();
2180 }
2181
2182 result_type w = lambert_wm1(z, pol);
2183 return w/(z*(1+w));
2184 }
2185
2186 template <typename T>
2187 inline typename tools::promote_args<T>::type
2188 lambert_wm1_prime(T z)
2189 {
2190 return lambert_wm1_prime(z, policies::policy<>());
2191 }
2192
2193 }}
2194
2195 #endif
2196