racket/collects/math/private/functions/psi.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

251 lines
10 KiB
Racket

#lang typed/racket/base
(require "../../flonum.rkt"
"../../base.rkt"
"../polynomial/chebyshev.rkt"
"../number-theory/bernoulli.rkt"
"gamma.rkt"
"hurwitz-zeta.rkt"
"tan-diff.rkt")
(provide flpsi0 flpsi psi0 psi)
(: flpsi0-huge (Flonum -> Flonum))
;; Compute using first two terms from asymptotic expansion
;; Error <= 1 ulp for x >= 1e7
(define (flpsi0-huge x)
(fl- (fllog x) (fl/ 0.5 x)))
(: flpsi0-large (Flonum -> Flonum))
;; Compute using more terms from asymptotic expansion
;; Error <= 1 ulp for x >= 44
(define (flpsi0-large x)
(define 1/x (/ 1.0 x))
(define 1/x^2 (* 1/x 1/x))
(+ (fllog x)
(let* ([y (* 1/x^2 #i-1/252)]
[y (* 1/x^2 (+ #i1/120 y))]
[y (* 1/x (+ #i-1/12 y))])
(* 1/x (+ -0.5 y)))))
(: flpsi0-15-44 (Flonum -> Flonum))
;; Compute using Chebyshev fit of transformed function
;; Error <= 1 ulp for 15 <= x <= 44
(define (flpsi0-15-44 x)
(define y
((inline-chebyshev-flpoly-fun
15.0 44.0
(-2.651473128433205899236218386166733001125e6
-1.762146136898477454946670140604454842406e6
-5.717880156460911821842439315667552305722e5
-8.999795051532912396661010381758994001778e4
-5.525632813934147220013901752731996650924e3
+3.730714289863418037571565563246348880127e-7
-9.689086103062769553596723282091729538813e-8
+2.512217593011105663102858605710866764550e-8
-6.502769240064928944990050767511278012820e-9
+1.679934847962426417907078746025458161173e-9
-4.316007423661544654578361918157615904084e-10
+1.042642491290735190419839693626327816406e-10))
x))
(+ (/ y (flexpt x 5.0)) (fllog x) (/ 0.5 x)))
(: flpsi0-6-15 (Flonum -> Flonum))
;; Error <= 1 ulp for 6 <= x <= 15
(define (flpsi0-6-15 x)
(define y
((inline-chebyshev-flpoly-fun
6.0 15.0
(-1.925244301146350628816428684716550045429e4
-1.198353263149330621624048804034028776287e4
-3.477937539308286982692458873651726693812e3
-4.803046790639916261784265178273773686249e2
-2.562890803820053728218998699641891321552e1
+3.740788808963323665370593041281819399850e-7
-7.713638977946100306711746793694236435924e-8
+1.565178892640717100414675722794707618947e-8
-3.117542465640122863625790111806482043942e-9
+6.073503129025465167965511518460566324779e-10
-1.150949496047179890084998241564162255119e-10
+2.102858491281106124889246275868833089257e-11
-3.647260410862808863678434035974178985902e-12
+5.827390822374468084948661977003242859188e-13
-7.999114123557451949902041477681255993810e-14))
x))
(+ (/ y (flexpt x 5.0)) (fllog x)))
(: flpsi0-1.9-3 (Flonum -> Flonum))
(define (flpsi0-1.9-3 x)
(define y
((inline-chebyshev-flpoly-fun
1.9 3.0
(-1.068595135558250365970154135318779762977
0.007555110290613685894455357538792217876164
-8.211196131506054788097165956947618267216e-4
8.819898077656088066728485086945404403996e-5
-9.377207860942770361265708932757532015772e-6
9.882656181596999489012188167296378462293e-7
-1.033878691914051272793824247210082411098e-7
1.075053486743124253187897895133480499813e-8
-1.112459077942683078328275732383680238168e-9
1.146881360570377686259482136117612783879e-10
-1.179172668817595317199544685547649548159e-11
1.210211518974043571256683371091400286333e-12
-1.240872724505738918165638170689453141739e-13
1.272005760582855661944481497028186095588e-14
-1.304284165442490577500377306573196471693e-15
1.324746805869742319628788142120853886066e-16))
x))
(+ (/ y (flexpt x 1.0)) (fllog x)))
(: flpsi0-pos-zero (Flonum -> Flonum))
;; Error <= 2 ulp for 1.01 <= x <= 1.9
(define (flpsi0-pos-zero x)
((make-flpolyfun
(1.0585432012233855e-08
+9.6767223576078877096707761813142672147231142e-1
-4.42763160500353127553797599467585510491966309e-1
+2.58499753782129775648776735361540543429029315e-1
-1.63942699544933748044376456834206467101233261e-1
+1.07824045952487191135128855124325739325915008e-1
-7.21995575193409626696893908469264780134510431e-2
+4.8804285262128765080401907661996397609430272e-2
-3.31611242500726233186197345853966159593666507e-2
+2.25976465448926011125449117808694365399392534e-2
-1.54247646368189203846188963269378209631264895e-2
+1.0538790670881555307791836736009529596710663e-2
-7.20453368572977191622981741327584775896463279e-3
+4.92678087965504785805744172756649359819423221e-3
-3.36980127720035923906475716305572919765314786e-3
+2.30512605073145773629820036982065731913189791e-3
-1.57693657080739955525227889461909068304999766e-3
+1.07882505658776450345367614926996141127935916e-3
-7.3807083404537248486922908431997361289422551e-4
+5.04953190252646215739884819303074593735197609e-4
-3.45467970810508971431806463930371137534420811e-4
+2.36355976724137594774864968876273185881939724e-4
-1.61706193084464479583646631218793971111171482e-4
+1.10633707815531817492134312083342362402565131e-4
-7.56917816597543344357441178188820822372883337e-5
+5.1785747875351335968463825889133484772977912e-5
-3.54300637882398506423667399737040919259208752e-5
+2.42400610389497340053120082460952804952267374e-5
-1.65842386724073585234799128562703946147149189e-5
+1.13463820371245229094354235118485703293845643e-5
-7.76281586742261875732585414254027665196056168e-6
))
(- x 1.46163215590743)))
(: flpsi0-taylor-1 (Flonum -> Flonum))
;; Error <= 1 ulp for 0.75 <= x <= 1.23
(define (flpsi0-taylor-1 x)
((make-flpolyfun
(-5.77215664901532860606512090082402431042159336e-1
+1.6449340668482264364724151666460251892189499
-1.20205690315959428539973816151144999076498629
+1.08232323371113819151600369654116790277475095
-1.03692775514336992633136548645703416805708092
+1.01734306198444913971451792979092052790181749
-1.00834927738192282683979754984979675959986356
+1.00407735619794433937868523850865246525896079
-1.00200839282608221441785276923241206048560585
+1.00099457512781808533714595890031901700601953
-1.00049418860411946455870228252646993646860644
+1.00024608655330804829863799804773967096041609
-1.00012271334757848914675183652635739571427511
+1.0000612481350587048292585451051353337474817
-1.00003058823630702049355172851064506258762795
+1.00001528225940865187173257148763672202323739
-1.00000763719763789976227360029356302921308825
+1.0000038172932649998398564616446219397304547
-1.00000190821271655393892565695779510135325857
+1.00000095396203387279611315203868344934594379
-1.00000047693298678780646311671960437304596645
+1.00000023845050272773299000364818675299493504
-1.00000011921992596531107306778871888232638726
+1.0000000596081890512594796124402079358012275
-1.00000002980350351465228018606370506936601184
+1.00000001490155482836504123465850663069862886
-1.00000000745071178983542949198100417060411946))
(fl- x 1.0)))
(define pi^2/6 1.644934066848226436472415166646025189221)
(define -zeta3.0 -1.202056903159594285399738161511449990768)
(define pi^4/90 1.082323233711138191516003696541167902776)
(: flpsi0-tiny (Flonum -> Flonum))
(define (flpsi0-tiny x)
(+ (/ -1.0 x)
(- gamma.0)
(* x (+ pi^2/6 (* x (+ -zeta3.0 (* x pi^4/90)))))))
(: flpsi0-negative (Flonum -> Flonum))
(define (flpsi0-negative x)
(cond [(and (x . > . -inf.0) (not (integer? x)))
(- (flpsi0 (- 1.0 x)) (* pi (flcotpix x)))]
[else +nan.0]))
(: flpsi0 (Flonum -> Flonum))
(define (flpsi0 x)
(cond [(x . < . 3.0)
(cond [(x . < . 0.75)
(cond [(x . < . -0.0007) (flpsi0-negative x)]
[(x . < . 0.0007) (flpsi0-tiny x)]
[else (+ (/ -1.0 x) (flpsi0-pos-zero (+ x 1.0)))])]
[(x . < . 1.125) (flpsi0-taylor-1 x)]
[(x . < . 1.9) (flpsi0-pos-zero x)]
[else (flpsi0-1.9-3 x)])]
[(x . < . 6.0)
(cond [(x . < . 4.0)
(+ (/ -1.0 (+ x 2.0)) (/ -1.0 (+ x 1.0)) (/ -1.0 x) (flpsi0-6-15 (+ x 3.0)))]
[(x . < . 5.0)
(+ (/ -1.0 (+ x 1.0)) (/ -1.0 x) (flpsi0-6-15 (+ x 2.0)))]
[else (+ (/ -1.0 x) (flpsi0-6-15 (+ x 1.0)))])]
[(x . < . 15.0) (flpsi0-6-15 x)]
[(x . < . 44.0) (flpsi0-15-44 x)]
[(x . < . 1e7) (flpsi0-large x)]
[(x . < . +inf.0) (flpsi0-huge x)]
[(x . = . +inf.0) +inf.0]
[else +nan.0]))
(define pi.128 267257146016241686964920093290467695825/85070591730234615865843651857942052864)
(: flexppi (Flonum -> Flonum))
(define flexppi (make-flexpt pi.128))
(: flpsi (Integer Flonum -> Flonum))
(define (flpsi m x)
(cond [(m . < . 0) +nan.0]
[(m . = . 0) (flpsi0 x)]
[(x . fl> . 0.0)
(define sgn (if (even? m) -1.0 1.0))
(define m+1 (fl+ (fl m) 1.0))
(fl* (fl* sgn (flgamma m+1)) (flhurwitz-zeta m+1 x))]
[(integer? x)
(cond [(even? m) (if (fl= 0.0 x) (/ -1.0 x) +nan.0)]
[else +inf.0])]
[(and (x . fl> . -inf.0) (x . fl< . 0.0))
(define sgn (if (even? m) 1.0 -1.0))
(define t
(fl* (flexppi (fl+ (fl m) 1.0))
(flcot-diff/y m (flcotpix x))))
(fl- (fl* sgn (flpsi m (fl- 1.0 x))) t)]
[else +nan.0]))
(: psi0 (Real -> Flonum))
(define (psi0 x)
(cond [(flonum? x) (flpsi0 x)]
[(single-flonum? x) (flpsi0 (fl x))]
[(and (integer? x) (x . <= . 0))
(raise-argument-error 'psi0 "Real, not Zero or Negative-Integer" x)]
[else (flpsi0 (fl x))]))
(: psi (Integer Real -> Flonum))
(define (psi m x)
(cond [(m . < . 0) (raise-argument-error 'psi "Natural" 0 m x)]
[(flonum? x) (flpsi m x)]
[(single-flonum? x) (flpsi m (fl x))]
[(and (integer? x) (x . <= . 0))
(raise-argument-error 'psi "Real, not Zero or Negative-Integer" 1 m x)]
[else (flpsi m (fl x))]))