v0.15.5
Loading...
Searching...
No Matches
lambert_w_iter.hpp
Go to the documentation of this file.
1
2// Copyright Balazs Cziraki 2016.
3// Use, modification and distribution are subject to the
4// Boost Software License, Version 1.0. (See accompanying file
5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef BOOST_MATH_LAMBERT_W_ITER_HPP_INCLUDED
8#define BOOST_MATH_LAMBERT_W_ITER_HPP_INCLUDED
9
10#include <cmath>
11#include "lambert_w_tools.hpp"
12
13namespace boost
14{
15namespace math
16{
17namespace lambw
18{
19 //Fritsch's iteration for the Lambert W function with index k. It is a fast approximation that works for complex arguments,
20 //but preliminary tests using gnuplot revealed numeric weaknesses for poor starting approximations.
21 template<class ArgumentType, class CoeffType, class IndexType>
22 void _iter_frit(const ArgumentType &x, const IndexType& k, ArgumentType &Wn)
23 {
24 using std::log;
25 using std::abs;
26 using std::exp;
27
28 if((k!=0 && k!=-1) || (x!=(CoeffType)0. && x!=(ArgumentType)(-rec_e<CoeffType>())))
29 {
30 ArgumentType z_n;
31
32 if(k==0)
33 {
34 if(_complex_imag(x)==0
35 &&(_complex_real(x)<=0)
36 &&(_complex_real(x)>=-rec_e<CoeffType>()) )
37 {
38 z_n = log(-x)-log(-Wn)-Wn;
39 }
40 else
41 {
42 z_n = log(x)-log(Wn)-Wn;
43 }
44 }
45 else
46 {
47 if((k==-1)&&(_complex_imag(x)==0)
48 &&(_complex_real(x)<=0)
49 &&(_complex_real(x)>=-rec_e<CoeffType>()))
50 {
51 z_n = log(-x)-log(-Wn)-Wn;
52 }
53 else
54 {
55 z_n = _log_k(x,k)+log((CoeffType)1./Wn)-Wn;
56 }
57 }
58
59 ArgumentType q_n=(CoeffType)2.*((CoeffType)1.+Wn)*((CoeffType)1.+Wn+(CoeffType)2./(CoeffType)3.*z_n);
60
61 ArgumentType e_n=z_n/((CoeffType)1.+Wn)*(q_n-z_n)/(q_n-(CoeffType)2.*z_n);
62
63 Wn *= ((CoeffType)1.+e_n);
64 }
65 }
66
67 //Calculates Newton's method without logarithms for W_k(z).
68 //Newton's method was chosen instead of Halley's because Halley's method tended to overflow for large arguments.
69 template<class ArgumentType, class CoeffType, class IndexType>
70 void _iter_newt_nolog(const ArgumentType &x, ArgumentType &fn)
71 {
72 using std::exp;
73
74 fn += -fn/((CoeffType)1.+fn)+x/((CoeffType)1.+fn)*exp(-fn);
75 }
76
77 //Calculates Newton's method with logarithms. This version works for large arguments.
78 template<class ArgumentType, class CoeffType, class IndexType>
79 void _iter_newt_wlog(const ArgumentType &x, ArgumentType &fn)
80 {
81 using std::exp;
82 using std::log;
83
84 if(_complex_real(x)<0)
85 {
86 if(_complex_real(fn)<0)
87 {
88 fn += -fn/((CoeffType)1.+fn)+exp(log(-x)-log(-(CoeffType)1.-fn)-(fn));
89 }
90 else
91 {
92 fn += -fn/((CoeffType)1.+fn)-exp(log(-x)-log((CoeffType)1.+fn)-(fn));
93 }
94 }
95 else
96 {
97 if(_complex_real(fn)<0)
98 {
99 //return fn-(CoeffType)1./((CoeffType)1.+(CoeffType)1./fn)-exp(log(x)-log(-(CoeffType)1.-fn)-(fn));
100 fn += -fn/((CoeffType)1.+fn)-exp(log(x)-log(-(CoeffType)1.-fn)-(fn));
101 }
102 else
103 {
104 fn += -fn/((CoeffType)1.+fn)+exp(log(x)-log((CoeffType)1.+fn)-(fn));
105 }
106 }
107 }
108
109 //Chooses which version of Newton's method to use and returns the value.
110 template<class ArgumentType, class CoeffType, class IndexType>
111 void _iter_newt(const ArgumentType &x, const IndexType& k, ArgumentType &fn)
112 {
113 using std::abs;
114 using std::exp;
115
116 if(((((k==0)||(k==-1))&&(_complex_imag(x)>=0))
117 ||((k==1)&&(_complex_imag(x)<0)))
118 &&(abs(x+rec_e<CoeffType>())<7e-4))
119 {
120
121 }
122 else
123 {
124 if(((k==0)&&(abs(x)<rec_e<CoeffType>()))
125 ||(k==-1&&_complex_imag(x)>=0&&abs(x+rec_e<CoeffType>())<0.3)
126 ||(k==1&&_complex_imag(x)<0&&abs(x+rec_e<CoeffType>())<0.3))
127 {
128 _iter_newt_nolog<ArgumentType,CoeffType,IndexType>(x,fn);
129 }
130 else
131 {
132 _iter_newt_wlog<ArgumentType,CoeffType,IndexType>(x,fn);
133 }
134 }
135 }
136} //namespace lambw
137} //namespace math
138} //namespace boost
139
140#endif // BOOST_MATH_LAMBERT_W_ITER_HPP_INCLUDED
FTensor::Index< 'k', 3 > k
void _iter_frit(const ArgumentType &x, const IndexType &k, ArgumentType &Wn)
void _iter_newt(const ArgumentType &x, const IndexType &k, ArgumentType &fn)
void _iter_newt_nolog(const ArgumentType &x, ArgumentType &fn)
ArgumentType _log_k(const ArgumentType &z, const IndexType &k)
void _iter_newt_wlog(const ArgumentType &x, ArgumentType &fn)
CoeffType _complex_imag(const CoeffType &z)
CoeffType _complex_real(const CoeffType &z)