racket/collects/math/private/functions/zeta.rkt
Neil Toronto 055512b4e8 Renamed make-flexp/base' to make-flexpt'
Renamed `dist' struct type to `distribution' ("dist" is too common)
2012-12-03 22:45:31 -07:00

206 lines
7.3 KiB
Racket

#lang typed/racket/base
#|
Algorithm for the majority of eta's domain from
P. Borwein. An Efficient Algorithm for the Riemann Zeta Function.
|#
(require racket/fixnum
"../../flonum.rkt"
"../../base.rkt"
"../number-theory/factorial.rkt"
"../number-theory/bernoulli.rkt"
"../polynomial/chebyshev.rkt"
"gamma.rkt"
"stirling-error.rkt")
(provide fleta flzeta
eta zeta)
(define +eta-max.0 53.99999999955306)
(define +zeta-max.0 53.000000000670404)
;; Error <= 1 ulp for 0 <= x <= 0.04
(define fleta-taylor-0
(make-flpolyfun
(0.5
+2.25791352644727432363097614947441071785897339e-1
-3.05145718840280522586220206685108673985433522e-2
-3.91244691530275106760124536428014526534772501e-3
+2.08483152359513300940797999527700394516178740e-3
-3.12274485703922093874348990729689586909277588e-4
+4.77866286231754699184106581473688337626826621e-6
+6.81492916627787647157234076681326635240242752e-6)))
(define fleta-cheby-0-1
(inline-chebyshev-flpoly-fun
0.0 1.0
(1.201451085000215786341948016934590750096
0.09659235221993630986901377398183709103273
-0.004162536123697811956855631042802249558704
-1.823459118570897951644789418281880496971e-5
1.057437661524516894212763161453537729375e-5
-5.276357969271112185781725261857608168314e-7
9.552883431770909233660820857569776676994e-9
2.861275947684961245106758674027061705788e-10
-2.592164434350750739588078107978177224236e-11
8.915497281646523022154515860475428889141e-13
-1.447759589742495761488938114822542491701e-14
-1.629339340198539399979819526388023402444e-16
1.846901346319333008905200116299163652954e-17)))
(define fleta-cheby-neg-1.5-0
(inline-chebyshev-flpoly-fun
-1.5 0.0
(0.6249707175603271538769600167574752420857
0.1919290294856821784120025035346336182627
-0.003267513343418322858117903176882496211178
-0.001266607295556663909608241164197267248528
1.229333530745096620548304292135771666374e-4
-2.895947350460977592953532943362896903995e-6
-3.416581692876350748659539557978633940172e-7
3.837933497475585903016599027301413075615e-8
-1.775011660163000411058608111537020096243e-9
1.823510907947069149164464718906140458455e-11
3.270513023690372128256583347736563273382e-12
-2.650468446042741339295818711051485655948e-13
1.078303611477515364506213006324611739967e-14
-1.971960766890138166024311496731213878603e-16
-5.923220277992641912614957330192473539923e-18)))
(: make-ds (Positive-Index -> FlVector))
(define (make-ds n)
(define ds
(cdr
(reverse
(for/fold: ([lst : (Listof Real) (list 0)]) ([i (in-range (+ n 1))])
(cons (+ (car lst)
(/ (* n (factorial (+ n i -1)) (expt 4 i))
(* (factorial (- n i)) (factorial (* 2 i)))))
lst)))))
(apply flvector (map fl ds)))
(define n 22) ; 21 is enough to get about 16 digits; one more plays it safe
(define ds (make-ds n))
(define dn (flvector-ref ds n))
(: fleta-borwein (Flonum -> Flonum))
;; Error <= 4 ulp for s > 0
(define (fleta-borwein s)
(let: loop : Flonum ([y : Flonum 0.0]
[sgn : Flonum 1.0]
[k : Nonnegative-Fixnum 0])
(cond [(k . fx< . n)
(define dy (fl/ (fl* sgn (fl- dn (flvector-ref ds k)))
(fl* dn (flexp (fl* s (fllog (+ (fl k) 1.0)))))))
(define new-y (fl+ y dy))
(cond [((flabs dy) . fl<= . (fl* (fl* 0.5 epsilon.0) (flabs new-y)))
new-y]
[else
(loop new-y (fl* sgn -1.0) (fx+ k 1))])]
[else y])))
(define pi.64 14488038916154245685/4611686018427387904)
(define euler.64 12535862302449814171/4611686018427387904)
(define pi.128 267257146016241686964920093290467695825/85070591730234615865843651857942052864)
(: flexppi (Flonum -> Flonum))
(define flexppi (make-flexpt pi.128))
(require math/bigfloat)
(: fleta (Flonum -> Flonum))
(define (fleta s)
(cond [(s . fl> . 0.0)
(cond [(s . fl> . +eta-max.0) 1.0]
[(s . fl> . 1.0) (fleta-borwein s)]
[(s . fl> . 0.04) (fleta-cheby-0-1 s)]
[else (fleta-taylor-0 s)])]
[(s . fl< . 0.0)
(cond [(s . fl= . -inf.0) +nan.0]
[(s . fl< . -224.5)
(cond [(fleven? s) 0.0]
[(fleven? (fltruncate (* 0.5 s))) +inf.0]
[else -inf.0])]
[(s . fl< . -171.0)
(define f (make-flexpt (/ (* euler.64 pi.64) (inexact->exact (- s)))))
(* (/ 4.0 pi)
(flexp-stirling (- s))
(flsqrt (/ pi (* -0.5 s)))
(f (* 0.5 s))
(* s 0.5 (flsinpix (* s 0.5)))
(f (* 0.5 s)))]
[(s . fl< . -54.0)
(* (/ 4.0 pi)
(flexppi s)
(* s 0.5 (flsinpix (* s 0.5)))
(flgamma (- s)))]
[(s . fl< . -1.5)
(define 2^s-1 (- (flexpt 2.0 s) 1.0))
(* (/ 4.0 pi)
(flexppi s)
(* s 0.5 (flsinpix (* s 0.5)))
(flgamma (- s))
(fleta-borwein (- 1.0 s))
(/ (* 0.5 (- 2^s-1 1.0)) 2^s-1))]
[(s . fl< . -0.05)
(fleta-cheby-neg-1.5-0 s)]
[else
(fleta-taylor-0 s)])]
[(s . fl= . 0.0) 0.5]
[else +nan.0]))
(: flzeta (Flonum -> Flonum))
(define (flzeta s)
(cond [(s . fl> . +zeta-max.0) 1.0]
[(s . fl> . -171.0)
(define c
(cond [(s . fl< . -1.0) (- (- (fl/ 2.0 (flexpt 2.0 s)) 1.0))]
[else (- (flexpm1 (fl* (fl- 1.0 s) (fllog 2.0))))]))
(fl/ (fleta s) c)]
[(and (s . fl> . -266.5) (s . fl< . 0.0)) ; s < 0 keeps TR happy
(define f (make-flexpt (/ (* euler.64 pi.64) (inexact->exact (- s)))))
(* (/ 4.0 pi)
(flexp-stirling (- s))
(flsqrt (/ pi (* -0.5 s)))
(f (* 0.5 s))
(* s 0.5 (flsinpix (* s 0.5)))
(* (flexpt 2.0 (- s 1.0))
(- (flexpt 2.0 s) 1.0))
(f (* 0.5 s)))]
[(s . fl> . -inf.0)
(cond [(fleven? s) 0.0]
[(fleven? (fltruncate (* 0.5 s))) -inf.0]
[else +inf.0])]
[else +nan.0]))
(: eta (case-> (Nonpositive-Integer -> Exact-Rational)
(Flonum -> Flonum)
(Real -> Real)))
(define (eta s)
(cond [(flonum? s) (fleta s)]
[(single-flonum? s) (fleta (fl s))]
[(integer? s)
(cond [(zero? s) 1/2]
[(negative? s) (define k (- 1 s))
(* (/ (bernoulli-number k) k) (- (expt 2 k) 1))]
[else (fleta (fl s))])]
[else
(fleta (fl s))]))
(: zeta (case-> (Nonpositive-Integer -> Exact-Rational)
(Flonum -> Flonum)
(Real -> Real)))
(define (zeta s)
(cond [(flonum? s) (flzeta s)]
[(single-flonum? s) (flzeta (fl s))]
[(integer? s)
(cond [(zero? s) -1/2]
[(negative? s) (define k (- 1 s))
(- (/ (bernoulli-number k) k))]
[(eqv? s 1) (raise-argument-error 'zeta "Real, not One" s)]
[else (flzeta (fl s))])]
[else
(flzeta (fl s))]))