Skip to content

Commit cf35c58

Browse files
authored
Rewrite gamma_inc_taylor and gamma_inc_asym more concisely and eliminate allocations (#443)
1 parent 7f42b47 commit cf35c58

File tree

2 files changed

+40
-60
lines changed

2 files changed

+40
-60
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ IrrationalConstants = "0.1, 0.2"
2222
LogExpFunctions = "0.3.2"
2323
OpenLibm_jll = "0.7, 0.8"
2424
OpenSpecFun_jll = "0.5"
25-
julia = "1.3"
25+
julia = "1.5"
2626

2727
[extras]
2828
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"

src/gamma_inc.jl

Lines changed: 39 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -426,39 +426,29 @@ See also: [`gamma_inc(a,x,ind)`](@ref SpecialFunctions.gamma_inc)
426426
"""
427427
function gamma_inc_taylor(a::Float64, x::Float64, ind::Integer)
428428
acc = acc0[ind + 1]
429-
wk = zeros(30)
430-
flag = false
431-
apn = a + 1.0
432-
t = x/apn
433-
wk[1] = t
434-
loop = 2
435-
for indx = 2:20
429+
tolerance = 0.5acc
430+
431+
# compute first 21 terms
432+
ts = cumprod(ntuple(i -> x / (a + i), Val(21)))
433+
434+
# sum the smaller terms directly
435+
first_small_t = something(findfirst(<(1.0e-3), ts), 21)
436+
sm = t = ts[first_small_t]
437+
apn = a + first_small_t
438+
while t > tolerance
436439
apn += 1.0
437-
t *= x/apn
438-
if t <= 1.0e-3
439-
loop = indx
440-
flag = true
441-
break
442-
end
443-
wk[indx] = t
444-
end
445-
if !flag
446-
loop = 20
447-
end
448-
sm = t
449-
tol = 0.5*acc #tolerance
450-
while true
451-
apn += 1.0
452-
t *= x/apn
440+
t *= x / apn
453441
sm += t
454-
if t <= tol
455-
break
456-
end
457442
end
458-
for j = loop-1:-1:1
459-
sm += wk[j]
443+
444+
# sum terms from small to large
445+
last_large_t = first_small_t - 1
446+
for j last_large_t:(-1):1
447+
sm += ts[j]
460448
end
461-
p = (rgammax(a, x)/a)*(1.0 + sm)
449+
450+
p = (rgammax(a, x) / a) * (1.0 + sm)
451+
462452
return (p, 1.0 - p)
463453
end
464454

@@ -476,39 +466,29 @@ External links: [DLMF 8.11.2](https://dlmf.nist.gov/8.11.2)
476466
See also: [`gamma_inc(a,x,ind)`](@ref SpecialFunctions.gamma_inc)
477467
"""
478468
function gamma_inc_asym(a::Float64, x::Float64, ind::Integer)
479-
wk = zeros(30)
480-
flag = false
481469
acc = acc0[ind + 1]
482-
amn = a - 1.0
483-
t = amn/x
484-
wk[1] = t
485-
loop = 2
486-
for indx = 2:20
487-
amn -= 1.0
488-
t *= amn/x
489-
if abs(t) <= 1.0e-3
490-
loop = indx
491-
flag = true
492-
break
493-
end
494-
wk[indx] = t
495-
end
496-
if !flag
497-
loop = 20
498-
end
499-
sm = t
500-
while true
501-
if abs(t) < acc
502-
break
503-
end
504-
amn -= 1.0
505-
t *= amn/x
506-
sm += t
470+
471+
# compute first 21 terms
472+
ts = cumprod(ntuple(i -> (a - i) / x, Val(21)))
473+
474+
# sum the smaller terms directly
475+
first_small_t = something(findfirst(x -> abs(x) < 1.0e-3, ts), 21)
476+
sm = t = ts[first_small_t]
477+
amn = a - first_small_t
478+
while abs(t) acc
479+
amn -= 1.0
480+
t *= amn / x
481+
sm += t
507482
end
508-
for j = loop-1:-1:1
509-
sm += wk[j]
483+
484+
# sum terms from small to large
485+
last_large_t = first_small_t - 1
486+
for j in last_large_t:(-1):1
487+
sm += ts[j]
510488
end
511-
q = (rgammax(a, x)/x)*(1.0 + sm)
489+
490+
q = (rgammax(a, x) / x) * (1.0 + sm)
491+
512492
return (1.0 - q, q)
513493
end
514494

0 commit comments

Comments
 (0)