Skip to content

Commit 6e49782

Browse files
authored
fix overflow/underflow bug in zeta(z) (#129)
1 parent 803c969 commit 6e49782

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

src/gamma.jl

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,21 +402,32 @@ function zeta(s::ComplexOrReal{Float64})
402402
end
403403
return NaN*zero(s) # NaN + NaN*im
404404
elseif real(s) < 0.5
405-
if abs(real(s)) + abs(imag(s)) < 1e-3 # Taylor series for small |s|
405+
absim = abs(imag(s))
406+
if abs(real(s)) + absim < 1e-3 # Taylor series for small |s|
406407
return @evalpoly(s, -0.5,
407408
-0.918938533204672741780329736405617639861,
408409
-1.0031782279542924256050500133649802190,
409410
-1.00078519447704240796017680222772921424,
410411
-0.9998792995005711649578008136558752359121)
411412
end
412-
return zeta(1 - s) * gamma(1 - s) * sinpi(s*0.5) * (2π)^s / π
413+
if absim > 12 # amplitude of sinpi(s/2) ≈ exp(imag(s)*π/2)
414+
# avoid overflow/underflow (issue #128)
415+
lg = lgamma(1 - s)
416+
ln2pi = 1.83787706640934548356 # log(2pi) to double precision
417+
rehalf = real(s)*0.5
418+
return zeta(1 - s) * exp(lg + absim*(pi/2) + s*ln2pi) * (0.5/π) *
419+
Complex(sinpi(rehalf), copysign(cospi(rehalf), imag(s)))
420+
else
421+
return zeta(1 - s) * gamma(1 - s) * sinpi(s*0.5) * (2π)^s / π
422+
end
413423
end
414424

415425
m = s - 1
416426

417427
# shift using recurrence formula:
418428
# n is a semi-empirical cutoff for the Stirling series, based
419429
# on the error term ~ (|m|/n)^18 / n^real(m)
430+
# FIXME: slow for large imag(s) and small real(s)
420431
n = ceil(Int,6 + 0.7*abs(imag(s-1))^inv(1 + real(m)*0.05))
421432
ζ = one(s)
422433
for ν = 2:n

test/runtests.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ relerrc(z, x) = max(relerr(real(z),real(x)), relerr(imag(z),imag(x)))
5959
@test erfcx(1.8e88) erfcx(big(1.8e88)) rtol=4*eps()
6060

6161
@test_throws MethodError erf(big(1.0)*im)
62-
@test_throws MethodError erfi(big(1.0))
62+
@test_throws MethodError erfi(big(1.0))
6363
end
6464

6565
@testset "sine and cosine integrals" begin
@@ -475,11 +475,17 @@ end
475475
@test 1e-12 > relerrc(zeta(1e-3+1e-3im), -0.5009189365276307665899456585255302329444338284981610162-0.0009209468912269622649423786878087494828441941303691216750im)
476476
@test 1e-13 > relerrc(zeta(1e-4 + 2e-4im), -0.5000918637469642920007659467492165281457662206388959645-0.0001838278317660822408234942825686513084009527096442173056im)
477477

478-
# Issue #7169: (TODO: better accuracy should be possible?)
479-
@test 1e-9 > relerrc(zeta(0 + 99.69im), 4.67192766128949471267133846066040655597942700322077493021802+3.89448062985266025394674304029984849370377607524207984092848im)
478+
# Issue #7169:
479+
@test 1e-13 > relerrc(zeta(0 + 99.69im), 4.67192766128949471267133846066040655597942700322077493021802+3.89448062985266025394674304029984849370377607524207984092848im)
480480
@test 1e-12 > relerrc(zeta(3 + 99.69im), 1.09996958148566565003471336713642736202442134876588828500-0.00948220959478852115901654819402390826992494044787958181148im)
481-
@test 1e-9 > relerrc(zeta(-3 + 99.69im), 10332.6267578711852982128675093428012860119184786399673520976+13212.8641740351391796168658602382583730208014957452167440726im)
481+
@test 1e-13 > relerrc(zeta(-3 + 99.69im), 10332.6267578711852982128675093428012860119184786399673520976+13212.8641740351391796168658602382583730208014957452167440726im)
482482
@test 1e-13 > relerrc(zeta(2 + 99.69im, 1.3), 0.41617652544777996034143623540420694985469543821307918291931-0.74199610821536326325073784018327392143031681111201859489991im)
483+
484+
# issue #128
485+
@test 1e-13 > relerrc(zeta(.4 + 453.0im), 5.595631794716693 - 4.994584420588448im)
486+
@test 1e-10 > relerrc(zeta(.4 + 4053.0im), -0.1248993234383550+0.9195498409364987im)
487+
@test 1e-13 > relerrc(zeta(.4 + 12.01im), 1.0233184799021265846512208845-0.8008078492939259287905322251im)
488+
@test zeta(.4 + 12.01im) == conj(zeta(.4 - 12.01im))
483489
end
484490

485491
@testset "vectorization of 2-arg functions" begin

0 commit comments

Comments
 (0)