Skip to content

Commit f29c5c0

Browse files
cossiosimonbyrne
authored andcommitted
logerfcx (#203)
1 parent 5320155 commit f29c5c0

File tree

5 files changed

+52
-1
lines changed

5 files changed

+52
-1
lines changed

docs/src/functions_list.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ SpecialFunctions.erf
99
SpecialFunctions.erfc
1010
SpecialFunctions.erfcx
1111
SpecialFunctions.logerfc
12+
SpecialFunctions.logerfcx
1213
SpecialFunctions.erfi
1314
SpecialFunctions.dawson
1415
SpecialFunctions.erfinv

docs/src/functions_overview.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Here the *Special Functions* are listed according to the structure of [NIST Digi
3838
| [`erfcinv(x)`](@ref SpecialFunctions.erfcinv) | inverse function to [`erfc()`](@ref SpecialFunctions.erfc) |
3939
| [`erfcx(x)`](@ref SpecialFunctions.erfcx) | scaled complementary error function, i.e. accurate ``e^{x^2} \operatorname{erfc}(x)`` for large ``x`` |
4040
| [`logerfc(x)`](@ref SpecialFunctions.logerfc) | log of the complementary error function, i.e. accurate ``\operatorname{ln}(\operatorname{erfc}(x))`` for large ``x`` |
41+
| [`logerfcx(x)`](@ref SpecialFunctions.logerfcx) | log of the scaled complementary error function, i.e. accurate ``\operatorname{ln}(\operatorname{erfcx}(x))`` for large negative ``x`` |
4142
| [`erfi(x)`](@ref SpecialFunctions.erfi) | imaginary error function defined as ``-i \operatorname{erf}(ix)`` |
4243
| [`erfinv(x)`](@ref SpecialFunctions.erfinv) | inverse function to [`erf()`](@ref SpecialFunctions.erf) |
4344
| [`dawson(x)`](@ref SpecialFunctions.dawson) | scaled imaginary error function, a.k.a. Dawson function, i.e. accurate ``\frac{\sqrt{\pi}}{2} e^{-x^2} \operatorname{erfi}(x)`` for large ``x`` |

src/SpecialFunctions.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export
3535
erfi,
3636
erfinv,
3737
logerfc,
38+
logerfcx,
3839
eta,
3940
digamma,
4041
invdigamma,
@@ -65,7 +66,7 @@ include("betanc.jl")
6566
include("beta_inc.jl")
6667
include("deprecated.jl")
6768

68-
for f in (:digamma, :erf, :erfc, :erfcinv, :erfcx, :erfi, :erfinv, :logerfc,
69+
for f in (:digamma, :erf, :erfc, :erfcinv, :erfcx, :erfi, :erfinv, :logerfc, :logerfcx,
6970
:eta, :gamma, :invdigamma, :logfactorial, :lgamma, :trigamma, :ellipk, :ellipe)
7071
@eval $(f)(::Missing) = missing
7172
end

src/erf.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,3 +458,35 @@ end
458458

459459
logerfc(x::Real) = logerfc(float(x))
460460
logerfc(x::AbstractFloat) = throw(MethodError(logerfc, x))
461+
462+
@doc raw"""
463+
logerfcx(x)
464+
465+
Compute the natural logarithm of the scaled complementary error function of ``x``, that is
466+
467+
```math
468+
\operatorname{logerfcx}(x) = \operatorname{ln}(\operatorname{erfcx}(x))
469+
\quad \text{for} \quad x \in \mathbb{R} \, .
470+
```
471+
472+
This is the accurate version of ``\operatorname{ln}(\operatorname{erfcx}(x))`` for large and negative ``x``.
473+
474+
External links: [Wikipedia](https://en.wikipedia.org/wiki/Error_function).
475+
476+
See also: [`erfcx(x)`](@ref SpecialFunctions.erfcx).
477+
478+
# Implementation
479+
Based on the [`erfc(x)`](@ref SpecialFunctions.erfc) and [`erfcx(x)`](@ref SpecialFunctions.erfcx) functions.
480+
Currently only implemented for `Float32`, `Float64`, and `BigFloat`.
481+
"""
482+
function logerfcx(x::Union{Float32, Float64, BigFloat})
483+
# Don't include Float16 in the Union, otherwise logerfc would currently work for x <= 0.0, but not x > 0.0
484+
if x < 0.0
485+
return log(erfc(x)) + x^2
486+
else
487+
return log(erfcx(x))
488+
end
489+
end
490+
491+
logerfcx(x::Real) = logerfcx(float(x))
492+
logerfcx(x::AbstractFloat) = throw(MethodError(logerfcx, x))

test/erf.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@
2222
@test logerfc(Float32(10000)) log(erfc(BigFloat(10000, 100))) rtol=2*eps(Float32)
2323
@test logerfc(Float64(10000)) log(erfc(BigFloat(10000, 100))) rtol=2*eps(Float64)
2424

25+
@test_throws MethodError logerfcx(Float16(1))
26+
@test_throws MethodError logerfcx(Float16(-1))
27+
@test iszero(logerfcx(0))
28+
@test logerfcx(Float32(1)) -0.849605509933248248576017509499 rtol=2eps(Float32)
29+
@test logerfcx(Float64(1)) -0.849605509933248248576017509499 rtol=2eps(Float32)
30+
@test logerfcx(Float32(-1)) 1.61123231767807049464268192445 rtol=2eps(Float32)
31+
@test logerfcx(Float64(-1)) 1.61123231767807049464268192445 rtol=2eps(Float32)
32+
@test logerfcx(Float32(-100)) 10000.6931471805599453094172321 rtol=2eps(Float32)
33+
@test logerfcx(Float64(-100)) 10000.6931471805599453094172321 rtol=2eps(Float64)
34+
@test logerfcx(Float32(100)) -5.17758512266433257046678208395 rtol=2eps(Float32)
35+
@test logerfcx(Float64(100)) -5.17758512266433257046678208395 rtol=2eps(Float64)
36+
@test logerfcx(Float32(-1000)) 1.00000069314718055994530941723e6 rtol=2eps(Float32)
37+
@test logerfcx(Float64(-1000)) 1.00000069314718055994530941723e6 rtol=2eps(Float64)
38+
@test logerfcx(Float32(1000)) -7.48012072190621214066734919080 rtol=2eps(Float32)
39+
@test logerfcx(Float64(1000)) -7.48012072190621214066734919080 rtol=2eps(Float64)
40+
2541
@test_throws MethodError erfi(Float16(1))
2642
@test erfi(Float32(1)) 1.6504257587975428760 rtol=2*eps(Float32)
2743
@test erfi(Float64(1)) 1.6504257587975428760 rtol=2*eps(Float64)

0 commit comments

Comments
 (0)