Skip to content

Commit 6b5462f

Browse files
committed
fix JuliaLang#7169 (replace zeta function with new implementation)
1 parent 51047d7 commit 6b5462f

File tree

4 files changed

+95
-103
lines changed

4 files changed

+95
-103
lines changed

base/mpfr.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import
1313
isfinite, isinf, isnan, ldexp, log, log2, log10, max, min, mod, modf,
1414
nextfloat, prevfloat, promote_rule, rad2deg, rem, round, show,
1515
showcompact, sum, sqrt, string, print, trunc, precision, exp10, expm1,
16-
gamma, lgamma, digamma, erf, erfc, zeta, log1p, airyai, iceil, ifloor,
16+
gamma, lgamma, digamma, erf, erfc, zeta, eta, log1p, airyai, iceil, ifloor,
1717
itrunc, eps, signbit, sin, cos, tan, sec, csc, cot, acos, asin, atan,
1818
cosh, sinh, tanh, sech, csch, coth, acosh, asinh, atanh, atan2,
1919
serialize, deserialize, inf, nan, cbrt, typemax, typemin,
@@ -400,6 +400,19 @@ for f in (:exp, :exp2, :exp10, :expm1, :digamma, :erf, :erfc, :zeta,
400400
end
401401
end
402402

403+
# return log(2)
404+
function big_ln2()
405+
c = BigFloat()
406+
ccall((:mpfr_const_log2, :libmpfr), Cint, (Ptr{BigFloat}, Int32),
407+
&c, MPFR.ROUNDING_MODE[end])
408+
return c
409+
end
410+
411+
function eta(x::BigFloat)
412+
x == 1 && return big(-0.5)
413+
return -zeta(x) * expm1(big_ln2()*(1-x))
414+
end
415+
403416
function airyai(x::BigFloat)
404417
z = BigFloat()
405418
ccall((:mpfr_ai, :libmpfr), Int32, (Ptr{BigFloat}, Ptr{BigFloat}, Int32), &z, &x, ROUNDING_MODE[end])

base/special/gamma.jl

Lines changed: 63 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ function zeta(s::Union(Int,Float64,Complex{Float64}),
272272

273273
isnan(x) && return oftype(ζ, imag(z)==0 && isa(s,Int) ? x : Complex(x,x))
274274

275-
cutoff = 7 + real(m) # empirical cutoff for asymptotic series
275+
cutoff = 7 + real(m) + imag(m) # TODO: this cutoff is too conservative?
276276
if x < cutoff
277277
# shift using recurrence formula
278278
xf = floor(x)
@@ -407,112 +407,73 @@ lbeta(x::Number, w::Number) = lgamma(x)+lgamma(w)-lgamma(x+w)
407407
@vectorize_2arg Number beta
408408
@vectorize_2arg Number lbeta
409409

410-
const eta_coeffs =
411-
[.99999999999999999997,
412-
-.99999999999999999821,
413-
.99999999999999994183,
414-
-.99999999999999875788,
415-
.99999999999998040668,
416-
-.99999999999975652196,
417-
.99999999999751767484,
418-
-.99999999997864739190,
419-
.99999999984183784058,
420-
-.99999999897537734890,
421-
.99999999412319859549,
422-
-.99999996986230482845,
423-
.99999986068828287678,
424-
-.99999941559419338151,
425-
.99999776238757525623,
426-
-.99999214148507363026,
427-
.99997457616475604912,
428-
-.99992394671207596228,
429-
.99978893483826239739,
430-
-.99945495809777621055,
431-
.99868681159465798081,
432-
-.99704078337369034566,
433-
.99374872693175507536,
434-
-.98759401271422391785,
435-
.97682326283354439220,
436-
-.95915923302922997013,
437-
.93198380256105393618,
438-
-.89273040299591077603,
439-
.83945793215750220154,
440-
-.77148960729470505477,
441-
.68992761745934847866,
442-
-.59784149990330073143,
443-
.50000000000000000000,
444-
-.40215850009669926857,
445-
.31007238254065152134,
446-
-.22851039270529494523,
447-
.16054206784249779846,
448-
-.10726959700408922397,
449-
.68016197438946063823e-1,
450-
-.40840766970770029873e-1,
451-
.23176737166455607805e-1,
452-
-.12405987285776082154e-1,
453-
.62512730682449246388e-2,
454-
-.29592166263096543401e-2,
455-
.13131884053420191908e-2,
456-
-.54504190222378945440e-3,
457-
.21106516173760261250e-3,
458-
-.76053287924037718971e-4,
459-
.25423835243950883896e-4,
460-
-.78585149263697370338e-5,
461-
.22376124247437700378e-5,
462-
-.58440580661848562719e-6,
463-
.13931171712321674741e-6,
464-
-.30137695171547022183e-7,
465-
.58768014045093054654e-8,
466-
-.10246226511017621219e-8,
467-
.15816215942184366772e-9,
468-
-.21352608103961806529e-10,
469-
.24823251635643084345e-11,
470-
-.24347803504257137241e-12,
471-
.19593322190397666205e-13,
472-
-.12421162189080181548e-14,
473-
.58167446553847312884e-16,
474-
-.17889335846010823161e-17,
475-
.27105054312137610850e-19]
476-
477-
function eta(z::Union(Float64,Complex128))
478-
if z == 0
479-
return oftype(z, 0.5)
480-
end
481-
re, im = reim(z)
482-
if im==0 && re < 0 && re==round(re/2)*2
483-
return zero(z)
484-
end
485-
reflect = false
486-
if re < 0.5
487-
z = 1-z
488-
reflect = true
489-
end
490-
s = zero(z)
491-
for n = length(eta_coeffs):-1:1
492-
c = eta_coeffs[n]
493-
p = n^-z
494-
s += c * p
410+
# Riemann zeta function; algorithm is based on specializing the Hurwitz
411+
# zeta function above for z==1.
412+
function zeta(s::Union(Float64,Complex{Float64}))
413+
# blows up to ±Inf, but get correct sign of imaginary zero
414+
s == 1 && return NaN + zero(s) * imag(s)
415+
416+
if !isfinite(s) # annoying NaN and Inf cases
417+
isnan(s) && return imag(s) == 0 ? s : s*s
418+
if isfinite(imag(s))
419+
real(s) > 0 && return 1.0 - zero(s)*imag(s)
420+
imag(s) == 0 && return NaN + zero(s)
421+
end
422+
return NaN*zero(s) # NaN + NaN*im
423+
elseif real(s) < 0.5
424+
if abs(real(s)) + abs(imag(s)) < 1e-3 # Taylor series for small |s|
425+
return @evalpoly(s, -0.5,
426+
-0.918938533204672741780329736405617639861,
427+
-1.0031782279542924256050500133649802190,
428+
-1.00078519447704240796017680222772921424,
429+
-0.9998792995005711649578008136558752359121)
430+
end
431+
return zeta(1 - s) * gamma(1 - s) * sinpi(s*0.5) * (2π)^s / π
495432
end
496-
if reflect
497-
z2 = 2.0^z
498-
b = 2.0 - (2.0*z2)
499-
f = z2 - 2
500-
piz = pi^z
501-
502-
b = b/f/piz
503-
504-
return s * gamma(z) * b * cospi(z/2)
433+
434+
m = s - 1
435+
436+
# shift using recurrence formula:
437+
# n is a semi-empirical cutoff for the Stirling series, based
438+
# on the error term ~ (|m|/n)^18 / n^real(m)
439+
n = iceil(6 + 0.7*abs(imag(s-1))^inv(1 + real(m)*0.05))
440+
ζ = one(s)
441+
for ν = 2:n
442+
ζₒ= ζ
443+
ζ += inv(ν)^s
444+
ζ == ζₒ && break # prevent long loop for large m
505445
end
506-
return s
446+
z = 1 + n
447+
t = inv(z)
448+
w = t^m
449+
ζ += w * (inv(m) + 0.5*t)
450+
451+
t *= t # 1/z^2
452+
ζ += w*t * @pg_horner(t,m,0.08333333333333333,-0.008333333333333333,0.003968253968253968,-0.004166666666666667,0.007575757575757576,-0.021092796092796094,0.08333333333333333,-0.4432598039215686,3.0539543302701198)
453+
454+
return ζ
507455
end
508456

457+
zeta(x::Integer) = zeta(float64(x))
458+
zeta(x::Real) = oftype(float(x),zeta(float64(x)))
459+
zeta(z::Complex) = oftype(float(z),zeta(complex128(z)))
460+
@vectorize_1arg Number zeta
461+
462+
function eta(z::Union(Float64,Complex{Float64}))
463+
δz = 1 - z
464+
if abs(real(δz)) + abs(imag(δz)) < 7e-3 # Taylor expand around z==1
465+
return 0.6931471805599453094172321214581765 *
466+
@evalpoly(δz,
467+
1.0,
468+
-0.23064207462156020589789602935331414700440,
469+
-0.047156357547388879740146103148112380421254,
470+
-0.002263576552598880778433550956278702759143568,
471+
0.001081837223249910136105931217561387128141157)
472+
else
473+
return -zeta(z) * expm1(0.6931471805599453094172321214581765*δz)
474+
end
475+
end
509476
eta(x::Integer) = eta(float64(x))
510477
eta(x::Real) = oftype(float(x),eta(float64(x)))
511478
eta(z::Complex) = oftype(float(z),eta(complex128(z)))
512479
@vectorize_1arg Number eta
513-
514-
function zeta(z::Number)
515-
zz = 2^z
516-
eta(z) * zz/(zz-2)
517-
end
518-
@vectorize_1arg Number zeta

test/math.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,18 @@ end
303303
@test 1e-13 > errc(zeta(2 + 1im, -1.1), -1525.8095173321060982383023516086563741006869909580583246557 + 1719.4753293650912305811325486980742946107143330321249869576im)
304304

305305
@test @evalpoly(2,3,4,5,6) == 3+2*(4+2*(5+2*6)) == @evalpoly(2+0im,3,4,5,6)
306+
307+
@test 1e-14 > err(eta(1+1e-9), 0.693147180719814213126976796937244130533478392539154928250926)
308+
@test 1e-14 > err(eta(1+5e-3), 0.693945708117842473436705502427198307157819636785324430166786)
309+
@test 1e-13 > err(eta(1+7.1e-3), 0.694280602623782381522315484518617968911346216413679911124758)
310+
@test 1e-13 > err(eta(1+8.1e-3), 0.694439974969407464789106040237272613286958025383030083792151)
311+
@test 1e-13 > err(eta(1 - 2.1e-3 + 2e-3 * im), 0.69281144248566007063525513903467244218447562492555491581+0.00032001240133205689782368277733081683574922990400416791019im)
312+
@test 1e-13 > err(eta(1 + 5e-3 + 5e-3 * im), 0.69394652468453741050544512825906295778565788963009705146+0.00079771059614865948716292388790427833787298296229354721960im)
313+
@test 1e-12 > errc(zeta(1e-3+1e-3im), -0.5009189365276307665899456585255302329444338284981610162-0.0009209468912269622649423786878087494828441941303691216750im)
314+
@test 1e-13 > errc(zeta(1e-4 + 2e-4im), -0.5000918637469642920007659467492165281457662206388959645-0.0001838278317660822408234942825686513084009527096442173056im)
315+
316+
# Issue #7169: (TODO: better accuracy should be possible?)
317+
@test 1e-9 > errc(zeta(0 + 99.69im), 4.67192766128949471267133846066040655597942700322077493021802+3.89448062985266025394674304029984849370377607524207984092848im)
318+
@test 1e-12 > errc(zeta(3 + 99.69im), 1.09996958148566565003471336713642736202442134876588828500-0.00948220959478852115901654819402390826992494044787958181148im)
319+
@test 1e-9 > errc(zeta(-3 + 99.69im), 10332.6267578711852982128675093428012860119184786399673520976+13212.8641740351391796168658602382583730208014957452167440726im)
320+
@test 1e-13 > errc(zeta(2 + 99.69im, 1.3), 0.41617652544777996034143623540420694985469543821307918291931-0.74199610821536326325073784018327392143031681111201859489991im)

test/mpfr.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,3 +782,6 @@ i3 = itrunc(f)
782782
@test i3 == f
783783
@test i3+1 > f
784784
@test i3+1 >= f
785+
786+
err(z, x) = abs(z - x) / abs(x)
787+
@test 1e-60 > err(eta(BigFloat("1.005")), BigFloat("0.693945708117842473436705502427198307157819636785324430166786"))

0 commit comments

Comments
 (0)