-
Notifications
You must be signed in to change notification settings - Fork 104
Rewrite gamma_inc_taylor and gamma_inc_asym more concisely
#443
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
eb71c65
2363f8f
0b0a61a
46a7b39
4e2edc6
7ac105e
c095329
c058a2a
ee41ab7
83afebb
34229ef
482516c
8d37a34
36d24be
3e06e43
79bacae
1c41a3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -426,39 +426,30 @@ See also: [`gamma_inc(a,x,ind)`](@ref SpecialFunctions.gamma_inc) | |||||||||
| """ | ||||||||||
| function gamma_inc_taylor(a::Float64, x::Float64, ind::Integer) | ||||||||||
| acc = acc0[ind + 1] | ||||||||||
| wk = zeros(30) | ||||||||||
| flag = false | ||||||||||
| apn = a + 1.0 | ||||||||||
| t = x/apn | ||||||||||
| wk[1] = t | ||||||||||
| loop = 2 | ||||||||||
| for indx = 2:20 | ||||||||||
| apn += 1.0 | ||||||||||
| t *= x/apn | ||||||||||
| if t <= 1.0e-3 | ||||||||||
| loop = indx | ||||||||||
| flag = true | ||||||||||
| break | ||||||||||
| end | ||||||||||
| wk[indx] = t | ||||||||||
| end | ||||||||||
| if !flag | ||||||||||
| loop = 20 | ||||||||||
| end | ||||||||||
| sm = t | ||||||||||
| tol = 0.5*acc #tolerance | ||||||||||
| while true | ||||||||||
|
|
||||||||||
| # compute first 21 terms | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if summation in reverse order is necessary (something like #442 (comment) would be much simpler implementation-wise)? I wonder if there is any argument/comment regarding this choice in the original Fortran code - does anyone know where the current implementation was copied from? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In theory better for numerical stability and precision to do it this way, because otherwise you can lose the accumulated effect of the small components when they're very much smaller than the large components, but I don't know in practice if/when it affects results of this function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've found a couple possible sources, but I think I'm gathering that the impetus was to support arbitrarily low precision. Maybe with Float64 it works pretty much fine, which this package forces. But with lower precision, maybe the errors would add up too much if floating point math wasn't carefully managed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like @Sumegh-git and @simonbyrne were writing/reviewing the PR that introduced them, if they can comment :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
ACM TOMS (FREE ACCESS): https://dl.acm.org/doi/abs/10.1145/22721.23109
The original paper is mentioned in the code comments. SpecialFunctions.jl/src/gamma_inc.jl Lines 831 to 834 in fdf95ab
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! In that case maybe this is the FORTRAN code itself? https://jblevins.org/mirror/amiller/inc_gam.f90 |
||||||||||
| ts = cumprod(ntuple(i -> x / (a + i), Val(21))) | ||||||||||
| last_t = findfirst(<(1.0e-3), ts) | ||||||||||
| last_t = last_t === nothing ? 20 : last_t - 1 | ||||||||||
| next_t = last_t + 1 | ||||||||||
|
|
||||||||||
| # sum the smaller terms directly | ||||||||||
| sm = t = ts[next_t] | ||||||||||
| apn = a + next_t | ||||||||||
| tolerance = 0.5acc | ||||||||||
| while t > tolerance | ||||||||||
BioTurboNick marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
| apn += 1.0 | ||||||||||
| t *= x/apn | ||||||||||
| t *= x / apn | ||||||||||
| sm += t | ||||||||||
| if t <= tol | ||||||||||
| break | ||||||||||
| end | ||||||||||
| end | ||||||||||
| for j = loop-1:-1:1 | ||||||||||
| sm += wk[j] | ||||||||||
|
|
||||||||||
| # sum terms from small to large | ||||||||||
| for j ∈ last_t:(-1):1 | ||||||||||
| sm += ts[j] | ||||||||||
| end | ||||||||||
| p = (rgammax(a, x)/a)*(1.0 + sm) | ||||||||||
|
|
||||||||||
| p = (rgammax(a, x) / a) * (1.0 + sm) | ||||||||||
|
|
||||||||||
| return (p, 1.0 - p) | ||||||||||
| end | ||||||||||
|
|
||||||||||
|
|
@@ -476,39 +467,30 @@ External links: [DLMF 8.11.2](https://dlmf.nist.gov/8.11.2) | |||||||||
| See also: [`gamma_inc(a,x,ind)`](@ref SpecialFunctions.gamma_inc) | ||||||||||
| """ | ||||||||||
| function gamma_inc_asym(a::Float64, x::Float64, ind::Integer) | ||||||||||
| wk = zeros(30) | ||||||||||
| flag = false | ||||||||||
| acc = acc0[ind + 1] | ||||||||||
| amn = a - 1.0 | ||||||||||
| t = amn/x | ||||||||||
| wk[1] = t | ||||||||||
| loop = 2 | ||||||||||
| for indx = 2:20 | ||||||||||
| amn -= 1.0 | ||||||||||
| t *= amn/x | ||||||||||
| if abs(t) <= 1.0e-3 | ||||||||||
| loop = indx | ||||||||||
| flag = true | ||||||||||
| break | ||||||||||
| end | ||||||||||
| wk[indx] = t | ||||||||||
| end | ||||||||||
| if !flag | ||||||||||
| loop = 20 | ||||||||||
| end | ||||||||||
| sm = t | ||||||||||
| while true | ||||||||||
| if abs(t) < acc | ||||||||||
| break | ||||||||||
| end | ||||||||||
| amn -= 1.0 | ||||||||||
| t *= amn/x | ||||||||||
| sm += t | ||||||||||
|
|
||||||||||
| # compute first 21 terms | ||||||||||
| ts = cumprod(ntuple(i -> (a - i) / x, Val(21))) | ||||||||||
| last_t = findfirst(x -> abs(x) < 1.0e-3, ts) | ||||||||||
| last_t = last_t === nothing ? 20 : last_t - 1 | ||||||||||
| next_t = last_t + 1 | ||||||||||
|
|
||||||||||
| # sum the smaller terms directly | ||||||||||
| sm = t = ts[next_t] | ||||||||||
| amn = a - next_t | ||||||||||
| while abs(t) > acc | ||||||||||
BioTurboNick marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||
| amn -= 1.0 | ||||||||||
| t *= amn / x | ||||||||||
| sm += t | ||||||||||
| end | ||||||||||
| for j = loop-1:-1:1 | ||||||||||
| sm += wk[j] | ||||||||||
|
|
||||||||||
| # sum terms from small to large | ||||||||||
| for j in last_t:(-1):1 | ||||||||||
| sm += ts[j] | ||||||||||
| end | ||||||||||
| q = (rgammax(a, x)/x)*(1.0 + sm) | ||||||||||
|
|
||||||||||
| q = (rgammax(a, x) / x) * (1.0 + sm) | ||||||||||
|
|
||||||||||
| return (1.0 - q, q) | ||||||||||
| end | ||||||||||
|
|
||||||||||
|
|
||||||||||
Uh oh!
There was an error while loading. Please reload this page.