@@ -3,7 +3,7 @@ using Base.MathConstants
3
3
# barebones polynomial type supporting +, -, *
4
4
struct SimplePoly{T}
5
5
coeffs:: Vector{T}
6
- end
6
+ end
7
7
8
8
Base.:* (p:: SimplePoly , c) = SimplePoly (p. coeffs * c)
9
9
Base.:* (c, p:: SimplePoly ) = p * c
@@ -43,7 +43,7 @@ macro E₁_cf64(x, n::Integer)
43
43
# consider using BigFloat?
44
44
p, q = E₁_cfpoly_approx (n, Float64)
45
45
xesc = esc (x)
46
-
46
+
47
47
num_expr = :(@evalpoly $ xesc)
48
48
append! (num_expr. args, Float64 .(p. coeffs))
49
49
den_expr = :(@evalpoly $ xesc)
@@ -74,54 +74,22 @@ macro E₁_taylor64(z, n::Integer)
74
74
:( $ taylor - log ($ zesc) )
75
75
end
76
76
77
- # minimax rational approximations to E_1(x)/exp(-x)
78
- const num_2_4 = (3.600530862438501481559423277418128014798 ,
79
- 28.73031134165011013783185685393062481126 ,
80
- 46.04314409968065653003548224846863877481 ,
81
- 21.47189493062368074985000918414086604187 ,
82
- 2.719957622921613321844755385973197500235 ,
83
- 1.508750885580864752293599048121678438568e-6 )
84
- const denom_2_4 = (1.0 ,
85
- 18.06743589038646654075831055159865459831 ,
86
- 61.19456872238615922515377354442679999566 ,
87
- 64.81772518730116701207299231777089576859 ,
88
- 24.19034591054828198408354214931112970741 ,
89
- 2.720026796991567940556850921390829046015 )
90
-
91
- const num_4_10 = (3.149019890512432117647119992448352099575 ,
92
- 14.77395058090815888166486507990452627136 ,
93
- 14.78214309058953358717796744960600201013 ,
94
- 4.559401130686434886620102186841739864936 ,
95
- 0.4027858394909585103775445204576054721422 ,
96
- 2.302781920509468929446800686773538387432e-9 )
97
- const denom_4_10 = (1.0 ,
98
- 11.65960373479520446458792926669115987821 ,
99
- 26.20023773503894444535165299118172674849 ,
100
- 18.93899893550582921168134979000319186841 ,
101
- 4.962178168140565906794561070524079194193 ,
102
- 0.4027860481050182948737116109665534358805 )
103
-
104
- const num_10_20 = (2.564801308922428705318296668924369454617 ,
105
- 5.482252510134574167659359513298970499768 ,
106
- 2.379528224853089764405551768869103662657 ,
107
- 0.2523431276282591480166881146593592650031 ,
108
- 1.444719769329975045925053905197199934930e-9 ,
109
- - 8.977332061106791470409502623202677045468e-12 )
110
- const denom_10_20 = (1.0 ,
111
- 6.421214405318108272004472721910023284626 ,
112
- 7.609584052290707052877352911548283916247 ,
113
- 2.631866613851763364839413823973711355890 ,
114
- 0.2523432345539146248733539983749722854603 )
115
-
116
77
# adapted from Steven G Johnson's initial implementation: issue #19
117
78
function expint_opt (x:: Float64 )
118
79
x < 0 && throw (DomainError (x, " negative argument, convert to complex first" ))
119
80
x == 0 && return Inf
120
81
if x > 2.15
121
- x < 4.0 && return exp (- x) * evalpoly (x, num_2_4) / evalpoly (x, denom_2_4)
122
- x < 10.0 && return exp (- x) * evalpoly (x, num_4_10) / evalpoly (x, denom_4_10)
123
- x < 20.0 && return exp (- x) * evalpoly (x, num_10_20) / evalpoly (x, denom_10_20)
124
- x < 200.0 && return @E₁_cf64 (x, 8 )
82
+ # minimax rational approximations to E_1(x)/exp(-x):
83
+ x < 4.0 && return exp (- x) *
84
+ @evalpoly (x, 3.600530862438501481559423277418128014798 , 28.73031134165011013783185685393062481126 , 46.04314409968065653003548224846863877481 , 21.47189493062368074985000918414086604187 , 2.719957622921613321844755385973197500235 , 1.508750885580864752293599048121678438568e-6 ) /
85
+ @evalpoly (x, 1.0 , 18.06743589038646654075831055159865459831 , 61.19456872238615922515377354442679999566 , 64.81772518730116701207299231777089576859 , 24.19034591054828198408354214931112970741 , 2.720026796991567940556850921390829046015 )
86
+ x < 10.0 && return exp (- x) *
87
+ @evalpoly (x, 3.149019890512432117647119992448352099575 , 14.77395058090815888166486507990452627136 , 14.78214309058953358717796744960600201013 , 4.559401130686434886620102186841739864936 , 0.4027858394909585103775445204576054721422 , 2.302781920509468929446800686773538387432e-9 ) /
88
+ @evalpoly (x, 1.0 , 11.65960373479520446458792926669115987821 , 26.20023773503894444535165299118172674849 , 18.93899893550582921168134979000319186841 , 4.962178168140565906794561070524079194193 , 0.4027860481050182948737116109665534358805 )
89
+ x < 20.0 && return exp (- x) *
90
+ @evalpoly (x, 2.564801308922428705318296668924369454617 , 5.482252510134574167659359513298970499768 , 2.379528224853089764405551768869103662657 , 0.2523431276282591480166881146593592650031 , 1.444719769329975045925053905197199934930e-9 , - 8.977332061106791470409502623202677045468e-12 ) /
91
+ @evalpoly (x, 1.0 , 6.421214405318108272004472721910023284626 , 7.609584052290707052877352911548283916247 , 2.631866613851763364839413823973711355890 , 0.2523432345539146248733539983749722854603 )
92
+ x < 200.0 && return @E₁_cf64 (x, 8 ) # fallback continued fraction
125
93
return x < 740.0 ? @E₁_cf64 (x, 4 ) : 0.0 # underflow
126
94
else
127
95
# crossover point to taylor should be tuned more
@@ -178,7 +146,7 @@ function En_cf_nogamma(ν::Number, z::Number, n::Int=1000)
178
146
Aprev:: typeof (B) = 1
179
147
ϵ = 10 * eps (real (B))
180
148
scale = sqrt (floatmax (real (A)))
181
-
149
+
182
150
# two recurrence steps / loop
183
151
iters = 0
184
152
for i = 2 : n
@@ -190,26 +158,26 @@ function En_cf_nogamma(ν::Number, z::Number, n::Int=1000)
190
158
B′ = B
191
159
B = z* B + (i- 1 ) * Bprev
192
160
Bprev = B′
193
-
161
+
194
162
A′ = A
195
163
A = A + (ν+ i- 1 ) * Aprev
196
164
Aprev = A′
197
165
B′ = B
198
166
B = B + (ν+ i- 1 ) * Bprev
199
167
Bprev = B′
200
-
168
+
201
169
conv = abs (Aprev* B - A* Bprev) < ϵ* abs (B* Bprev)
202
170
conv && i > 4 && break
203
-
204
- # rescale
171
+
172
+ # rescale
205
173
if max (abs (real (A)), abs (imag (A))) > scale
206
174
A /= scale
207
175
Aprev /= scale
208
176
B /= scale
209
177
Bprev /= scale
210
178
end
211
179
end
212
-
180
+
213
181
exppart = exp (- z)
214
182
if abs (real (exppart)) == Inf && abs (imag (exppart)) == Inf
215
183
return exp (- z + log (A) - log (B)), iters
@@ -232,7 +200,7 @@ function En_cf_gamma(ν::Number, z::Number, n::Int=1000)
232
200
Aprev:: typeof (A) = 1
233
201
ϵ = 10 * eps (real (B))
234
202
scale = sqrt (floatmax (real (A)))
235
-
203
+
236
204
iters = 0
237
205
j = 1
238
206
for i = 2 : n
@@ -245,7 +213,7 @@ function En_cf_gamma(ν::Number, z::Number, n::Int=1000)
245
213
B′ = B
246
214
B = (i - ν)* B + term * Bprev
247
215
Bprev = B′
248
-
216
+
249
217
conv = abs (Aprev* B - A* Bprev) < ϵ* abs (B* Bprev)
250
218
conv && break
251
219
@@ -256,7 +224,7 @@ function En_cf_gamma(ν::Number, z::Number, n::Int=1000)
256
224
Bprev /= scale
257
225
end
258
226
end
259
-
227
+
260
228
gammapart = En_safe_gamma_term (ν, z)
261
229
cfpart = exp (- z)
262
230
if abs (real (cfpart)) == Inf || abs (imag (cfpart)) == Inf
@@ -268,7 +236,7 @@ function En_cf_gamma(ν::Number, z::Number, n::Int=1000)
268
236
return gammapart, - cfpart, iters
269
237
end
270
238
271
- # picks between continued fraction representations in
239
+ # picks between continued fraction representations in
272
240
# En_cf_nogamma and En_cf_gamma
273
241
# returns (evaluated result, # iterations used, whether En_cf_gamma was chosen)
274
242
function En_cf (ν:: Number , z:: Number , niter:: Int = 1000 )
@@ -290,17 +258,17 @@ function En_taylor(ν::Number, start::Number, z₀::Number, Δ::Number)
290
258
asum = a
291
259
Δ_prod_fact = - Δ
292
260
ϵ = 10 * eps (real (asum))
293
-
261
+
294
262
for k = 0 : 100
295
263
a_pre = Δ_prod_fact + a* Δ* (ν - k - 1 )/ (k + 1 )
296
264
a = a_pre / z₀
297
265
asum_prev = asum
298
266
asum += a
299
-
267
+
300
268
if abs (asum_prev - asum) < ϵ
301
269
break
302
270
end
303
-
271
+
304
272
Δ_prod_fact *= - Δ / (k + 2 )
305
273
end
306
274
@@ -329,15 +297,15 @@ function En_expand_origin(ν::Number, z::Number)
329
297
end
330
298
k += 1
331
299
end
332
-
300
+
333
301
return gammaterm - sumterm
334
302
end
335
303
336
304
# series about the origin, special case for integer n
337
305
# https://functions.wolfram.com/GammaBetaErf/ExpIntegralE/06/01/04/01/02/0005/
338
306
function En_expand_origin (n:: Integer , z:: Number )
339
307
gammaterm = 1 # (-z)^(n-1) / (n-1)!
340
- for i = 1 : n- 1
308
+ for i = 1 : n- 1
341
309
gammaterm *= - z / i
342
310
end
343
311
@@ -428,7 +396,7 @@ function expint(ν::Number, z::Number, niter::Int=1000)
428
396
rez, imz = real (z), abs (imag (z))
429
397
z = doconj ? conj (z) : z
430
398
ν = doconj ? conj (ν) : ν
431
-
399
+
432
400
quick_niter, nmax = 50 , 45
433
401
# start with small imaginary part if exactly on negative real axis
434
402
imstart = (imz == 0 ) ? abs (z)* sqrt (eps (typeof (real (z)))) : imz
@@ -444,7 +412,7 @@ function expint(ν::Number, z::Number, niter::Int=1000)
444
412
z₀ = rez + imstart* im
445
413
E_start, i, _ = En_cf (ν, z₀, quick_niter)
446
414
end
447
-
415
+
448
416
# nsteps chosen so |Δ| ≤ 0.5
449
417
nsteps = ceil (2 * (imstart - imz))
450
418
Δ = (imz - imstart)* im / nsteps
@@ -454,12 +422,12 @@ function expint(ν::Number, z::Number, niter::Int=1000)
454
422
E_start = En_taylor (ν, E_start, z₀, Δ)
455
423
z₀ += Δ
456
424
end
457
-
425
+
458
426
# more exact imaginary part available for non-integer ν
459
427
if imz == 0
460
428
E_start = real (E_start) + En_imagbranchcut (ν, z)
461
429
end
462
-
430
+
463
431
return doconj ? conj (E_start) : E_start
464
432
end
465
433
throw (" unreachable" )
0 commit comments