Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
# -*- coding=utf-8 -*-
2
#*****************************************************************************
3
#ö Copyright (C) 2010 Fredrik Strömberg <[email protected]>
4
#
5
# Distributed under the terms of the GNU General Public License (GPL)
6
#
7
# This code is distributed in the hope that it will be useful,
8
# but WITHOUT ANY WARRANTY; without even the implied warranty of
9
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
# General Public License for more details.
11
#
12
# The full text of the GPL is available at:
13
#
14
# http://www.gnu.org/licenses/
15
#*****************************************************************************
16
17
18
include "sage/ext/cdefs.pxi"
19
include "sage/ext/interrupt.pxi" # ctrl-c interrupt block support
20
include "sage/ext/stdsage.pxi" # ctrl-c interrupt block support
21
22
r"""
23
Low-precision algorithms for the K-Bessel function.
24
25
AUTHOR:
26
27
- Fredrik Strömberg (April 2010)
28
29
30
EXAMPLES::
31
32
33
sage: besselk_dp(10.0,5.0)
34
-0.7183327166568183
35
sage: besselk_dp_rec(10.0,3.0)
36
-6.3759939798738967e-08
37
sage: besselk_dp_rec(10.0,3.0,pref=1)
38
-0.42308698672505796
39
sage: besselk_dp_pow(10.0,3.0)
40
-6.3759939798739404e-08
41
sage: besselk_dp_pow(10.0,3.0,pref=1)
42
-0.42308698672506084
43
sage: a=besselk_dp_pow(10.0,3.0,pref=1);a
44
-0.42308698672506084
45
sage: b=besselk_dp_rec(10.0,3.0,pref=1);b
46
-0.42308698672505796
47
sage: abs(a-b)
48
2.886579864025407e-15
49
sage: besselk_dp_rec(100.0,3.0,pref=1)
50
0.082457701468151401
51
age: RF=RealField(150)
52
sage: CF=ComplexField(150)
53
sage: bessel_K(CF(100*I),RF(3))*exp(RF.pi()*RF(50))
54
0.0824577014681303
55
sage: _-besselk_dp_rec(100.0,3.0,pref=1)
56
-2.1094237467877974e-14
57
58
59
"""
60
61
cdef extern from "complex.h":
62
double complex _Complex_I
63
64
cdef extern from "math.h":
65
double log(double)
66
double exp(double)
67
double cos(double)
68
double sin(double)
69
double sinh(double)
70
double fabs(double)
71
int ceil(double)
72
double cabs(double complex)
73
double pow(double,double)
74
double complex clog(double complex)
75
double cimag(double complex)
76
double creal(double complex)
77
double carg(double complex)
78
79
#cdef from sage.functions.special:
80
# double log_gamma(double)
81
82
cdef double cppi =<double> 3.14159265358979323846264338327950288419716939 # =pi
83
cdef double pihalf=<double> 1.5707963267948966192313216916397514420985847 # =pi/2
84
cdef double ln2PI2= <double> 0.91893853320467274178032973640561763986139747 #=ln(2pi)/2
85
cdef double d_one =<double> 1.0
86
cdef double d_half =<double> 0.5
87
cdef double d_two =<double> 2.0
88
cdef double d_ten =<double> 10.0
89
cdef double d_20 =<double> 20.0
90
cdef double d_100 =<double> 100.0
91
cdef double complex c_one =<double complex> 1.0
92
cdef double complex c_zero =<double complex> 0.0
93
94
95
def besselk_dp(double R,double x,double prec=1e-14,int pref=0):
96
r"""
97
Modified K-Bessel function in double precision. Chooses the most appropriate algorithm.
98
99
INPUT:
100
101
- `R` -- parameter (double)
102
103
- `x` -- argument (double)
104
105
- `prec` -- precision (default 1E-14, double)
106
107
- `pref` -- use prefactor (integer, default 0)
108
109
= 1 => computes K_iR(x)*exp(pi*R/2)
110
111
= 0 => computes K_iR(x)
112
113
OUTPUT:
114
115
- exp(Pi*R/2)*K_{i*R}(x) -- double
116
117
EXAMPLES::
118
119
120
sage: besselk_dp_rec(10.0,5.0)
121
-0.7183327166568183
122
sage: besselk_dp_rec(10.0,3.0)
123
-6.3759939798738967e-08
124
sage: besselk_dp_rec(10.0,3.0,pref=1)
125
-0.42308698672505796
126
"""
127
if(R<0):
128
RR=-R
129
else:
130
RR=R
131
if(x<0):
132
raise ValueError," Need x>0! Got x=%s" % x
133
134
if(x<R*0.7):
135
try:
136
res=besselk_dp_pow(RR,x,prec,pref)
137
except ValueError:
138
res=besselk_dp_rec(RR,x,prec,pref)
139
else:
140
res=besselk_dp_rec(RR,x,prec,pref)
141
return res
142
143
def besselk_dp_rec(double R,double x,double prec=1e-14,int pref=0): # |r| <<1000, x >> 0 !
144
r"""
145
Modified K-Bessel function in double precision using the backwards Miller-recursion algorithm.
146
147
INPUT:
148
- ''R'' -- double
149
- ''x'' -- double
150
- ''prec'' -- (default 1E-12) double
151
- ''pref'' -- (default 1) int
152
=1 => computes K_iR(x)*exp(pi*R/2)
153
=0 => computes K_iR(x)
154
155
OUTPUT:
156
- exp(Pi*R/2)*K_{i*R}(x) -- double
157
158
EXAMPLES::
159
160
161
sage: besselk_dp_rec(10.0,5.0)
162
-0.7183327166568183
163
sage: besselk_dp_rec(10.0,3.0)
164
-6.3759939798738967e-08
165
sage: besselk_dp_rec(10.0,3.0,pref=1)
166
-0.42308698672505796
167
sage: besselk_dp_pow(10.0,3.0)
168
-6.3759939798739404e-08
169
sage: besselk_dp_pow(10.0,3.0,pref=1)
170
-0.42308698672506084
171
sage: a=besselk_dp_pow(10.0,3.0,pref=1);a
172
-0.42308698672506084
173
sage: b=besselk_dp_rec(10.0,3.0,pref=1);b
174
-0.42308698672505796
175
sage: abs(a-b)
176
2.886579864025407e-15
177
sage: besselk_dp_rec(100.0,3.0,pref=1)
178
0.082457701468151401
179
age: RF=RealField(150)
180
sage: CF=ComplexField(150)
181
sage: bessel_K(CF(100*I),RF(3))*exp(RF.pi()*RF(50))
182
0.0824577014681303
183
sage: _-besselk_dp_rec(100.0,3.0,pref=1)
184
-2.1094237467877974e-14
185
186
187
"""
188
if(x<0):
189
raise ValueError,"X<0"
190
#! To make a specific test is time-consuming
191
cdef double p=0.25+R*R
192
cdef double q=2.0*(x-1.0)
193
cdef double t=0.0 #/*arbitrary*/
194
cdef double k=d_one #/*arbitrary*/;
195
cdef double err=d_one
196
cdef int NMAX=5000
197
cdef int n_start=1 #128
198
cdef double ef1=log(d_two*x/cppi)
199
cdef double mr
200
cdef int n=n_start
201
cdef double tmp,tmp2,ef,nr,mr_p1,mr_m1,efarg
202
cdef int nn
203
for nn from 1 <= nn <= NMAX:
204
err=fabs(t-k)
205
if(err < prec):
206
if(n>n_start+40):
207
break
208
n=n+20
209
t=k
210
y=d_one # !/*arbitrary*/1;
211
k=d_one
212
d=d_one
213
tmp=d_two*x-R*cppi
214
nr=<double> n
215
if(tmp>1300.0):
216
return 0.0
217
ef = exp((ef1 + tmp)/(d_two*nr))
218
mr_p1=<double> n+1 # m+1
219
mr=<double> n # m
220
for m from n >=m>=1:
221
mr_m1=<double> m-1 # m-1
222
y=(mr_m1+p/mr)/(q+(mr_p1)*(d_two-y))
223
k=ef*(d+y*k)
224
d=d*ef
225
mr_p1=mr
226
mr=mr_m1
227
if(k==0.0):
228
s='the K-bessel routine failed (k large) for x,R=%s,%s, value=%s'
229
raise ValueError,s%(x,R,k)
230
k=d_one/k;
231
if( k > 1E30 ): #something big...
232
s='the K-bessel routine failed (k large) for x,R=%s,%s, value=%s'
233
raise ValueError,s%(x,R,k)
234
if(nn>=NMAX):
235
s='the K-bessel routine failed (too many iterations) for x,R=%s,%s, value=%s'
236
raise ValueError,s%(x,R,k)
237
#!k= exp( pi*r/2) * K_ir( x) !
238
if(pref==1):
239
return k
240
else:
241
return k*exp(-cppi*R/d_two)
242
243
244
def besselk_dp_pow(double R,double x,prec=1E-12,pref=0):
245
r"""
246
Computes the modified K-Bessel function: K_iR(x) using power series.
247
248
INPUT:
249
250
- `R` -- parameter (double)
251
252
- `x` -- argument (double)
253
254
- `prec` -- precision (double)
255
256
- `pref` -- use prefactor (integer, default 0)
257
258
= 1 => computes K_iR(x)*exp(pi*R/2)
259
260
= 0 => computes K_iR(x)
261
262
OUTPUT:
263
264
- `res` -- double
265
266
EXAMPLES::
267
268
269
sage: besselk_dp_pow(10.0,3.0)
270
-6.3759939798739404e-08
271
sage: besselk_dp_pow(10.0,3.0,pref=1)
272
-0.42308698672506084
273
sage: a=besselk_dp_pow(10.0,3.0,pref=1);a
274
-0.42308698672506084
275
sage: b=besselk_dp_rec(10.0,3.0,pref=1);b
276
-0.42308698672505796
277
sage: abs(a-b)
278
2.886579864025407e-15
279
280
REFERENCES:
281
- A. Gil, J. Segura, and N. M. Temme, Evaluation of the modified Bessel function of the third kind of imaginary orders, J. Comput. Phys. 175 (2002), no. 2, 398-411.
282
283
284
"""
285
cdef double xh=d_half*x
286
cdef double xh2=xh*xh
287
cdef double complex iR
288
iR=_Complex_I*R
289
cdef double complex gamma0=my_lngamma(d_one,R)
290
cdef double sigma0=cimag(gamma0)
291
cdef double rsigma0=creal(gamma0)
292
cdef double th=R*log(xh)-sigma0
293
cdef double tmp_sin = sin(th)
294
cdef double tmp_cos = cos(th)
295
cdef double tmp_factor=sqrt(cppi/(R*sinh(cppi*R)))
296
cdef double f0=-tmp_factor*tmp_sin
297
cdef double Rsq=R*R
298
cdef double pi_halfR=pihalf*R
299
cdef double r0=R*tmp_factor*tmp_cos
300
cdef double r1=R*tmp_factor/(d_one+Rsq)*(tmp_cos+R*tmp_sin)
301
cdef double c0=d_one
302
cdef double rk1=r0 # r(k-1)
303
cdef double fk1=f0 # f(k-1)
304
cdef double summa=f0
305
cdef double exp_Pih_R=exp(pi_halfR)
306
cdef double fk=(fk1+rk1)/(d_one+Rsq)
307
cdef double rk=r1
308
cdef double ck=xh2
309
summa=summa+ck*fk
310
fk1=fk
311
rk1=r1
312
cdef double rk2=r0
313
cdef double ck1=ck
314
cdef int N_max=1000
315
cdef int k
316
for k from 2<=k<=N_max:
317
kk=<double> k
318
den=(kk*kk+Rsq)
319
fk=(kk*fk1+rk1)/den
320
rk=((d_two*kk-d_one)*rk1-rk2)/den
321
ck=xh2*ck1/kk
322
summa=summa+ck*fk
323
if(fabs(ck*fk/summa*exp_Pih_R)<prec):
324
break
325
fk1=fk
326
rk2=rk1
327
rk1=rk
328
ck1=ck
329
if(k>=N_max):
330
s="Maximum numbber of iterations reached x,R=%s,%s val=%s"
331
raise ValueError,s%(x,R,summa)
332
stat=1 #! We reached end of loop
333
if(pref==1):
334
res=summa*exp_Pih_R
335
else:
336
res=summa
337
return res
338
339
340
341
### Scaled Bernoulli numbers
342
cdef int num_ber=50
343
cdef double Ber[51] # Ber[n]=B[2n]/(2n*(2n-1))
344
345
Ber[ 1 ]= 0.083333333333333333333333333333333333333333333
346
Ber[ 2 ]= -0.0027777777777777777777777777777777777777777778
347
Ber[ 3 ]= 0.00079365079365079365079365079365079365079365079
348
Ber[ 4 ]= -0.00059523809523809523809523809523809523809523810
349
Ber[ 5 ]= 0.00084175084175084175084175084175084175084175084
350
Ber[ 6 ]= -0.0019175269175269175269175269175269175269175269
351
Ber[ 7 ]= 0.0064102564102564102564102564102564102564102564
352
Ber[ 8 ]= -0.029550653594771241830065359477124183006535948
353
Ber[ 9 ]= 0.17964437236883057316493849001588939669435025
354
Ber[ 10 ]= -1.3924322169059011164274322169059011164274322
355
Ber[ 11 ]= 13.402864044168391994478951000690131124913734
356
Ber[ 12 ]= -156.84828462600201730636513245208897382810426
357
Ber[ 13 ]= 2193.1033333333333333333333333333333333333333
358
Ber[ 14 ]= -36108.771253724989357173265219242230736483610
359
Ber[ 15 ]= 691472.26885131306710839525077567346755333407
360
Ber[ 16 ]= -1.5238221539407416192283364958886780518659077e7
361
Ber[ 17 ]= 3.8290075139141414141414141414141414141414141e8
362
Ber[ 18 ]= -1.0882266035784391089015149165525105374729435e10
363
Ber[ 19 ]= 3.4732028376500225225225225225225225225225225e11
364
Ber[ 20 ]= -1.2369602142269274454251710349271324881080979e13
365
Ber[ 21 ]= 4.8878806479307933507581516251802290210847054e14
366
Ber[ 22 ]= -2.1320333960919373896975058982136838557465453e16
367
Ber[ 23 ]= 1.0217752965257000775652876280535855003940110e18
368
Ber[ 24 ]= -5.3575472173300203610827709191969204484849041e19
369
Ber[ 25 ]= 3.0615782637048834150431510513296227581941868e21
370
Ber[ 26 ]= -1.8999917426399204050293714293069429029473425e23
371
Ber[ 27 ]= 1.2763374033828834149234951377697825976541634e25
372
Ber[ 28 ]= -9.2528471761204163072302423483476227795193312e26
373
Ber[ 29 ]= 7.2188225951856102978360501873016379224898404e28
374
Ber[ 30 ]= -6.0451834059958569677431482387545472860661444e30
375
Ber[ 31 ]= 5.4206704715700945451934778148261000136612022e32
376
Ber[ 32 ]= -5.1929578153140819467001947643918576846997063e34
377
Ber[ 33 ]= 5.3036588551197005966548392430697586436992926e36
378
Ber[ 34 ]= -5.7633253481649640138944358507809925551907376e38
379
Ber[ 35 ]= 6.6511557148484539375165201458105559510397394e40
380
Ber[ 36 ]= -8.1373783581366805387161726320935756918406892e42
381
Ber[ 37 ]= 1.0536966953357141803754804927641810189648373e45
382
Ber[ 38 ]= -1.4418180599962206261805377801511812809570332e47
383
Ber[ 39 ]= 2.0817356522089565462424808241263562311317343e49
384
Ber[ 40 ]= -3.1670226634886661827413495567742561342918070e51
385
Ber[ 41 ]= 5.0700064612111373431792648153174876567629628e53
386
Ber[ 42 ]= -8.5299728203005518816208400522162278887807045e55
387
Ber[ 43 ]= 1.5064172809340598576695117360379879076101931e58
388
Ber[ 44 ]= -2.7893494703831636871288381686312781712347569e60
389
Ber[ 45 ]= 5.4093504352860415005763561871884152582336290e62
390
Ber[ 46 ]= -1.0975337821508519855016788726170795167099903e65
391
Ber[ 47 ]= 2.3274876202618479173478641032052184930193480e67
392
Ber[ 48 ]= -5.1539291620653213901946552121717171770391159e69
393
Ber[ 49 ]= 1.1906210230890226457684816176871380462750227e72
394
Ber[ 50 ]= -2.8668938960296673696226420541900772462913819e74
395
396
397
def my_lngamma(double x,double R,double prec=1E-16):
398
r"""
399
Logarithm of Gamma function for the argument x+i*R
400
(using principal branch of the logarithm)
401
INPUT:
402
- ''x'' -- double
403
- ''R'' -- double
404
OUTPUT:
405
- ''my_loggamma' -- double complex = ln(Gamma(x+i*R))
406
407
EXAMPLES::
408
409
410
sage: timeit('my_lngamma(3.0)')
411
625 loops, best of 3: 7.01 \mu s per loop
412
sage: my_lngamma(3.0)
413
(-3.2441442995897556+1.053350771068613j)
414
sage: import mpmath
415
sage: a=mpmath.mpc(my_lngamma(3.0));a
416
mpc(real='-3.2441442995897556', imag='1.053350771068613')
417
sage: b=mpmath.loggamma(mpmath.mpc(1,3)); b
418
mpc(real='-3.244144299589756', imag='1.0533507710686132')
419
sage: a-b
420
mpc(real='4.4408920985006262e-16', imag='-2.2204460492503131e-16')
421
sage: abs(a-b)
422
mpf('4.9650683064945462e-16')
423
424
425
"""
426
cdef double a,jr,lnw,argw,Ims,Res,R2,S,r
427
cdef double complex cr,tmp, res,iR,d_c_i
428
cdef double complex z,w ,w2,ww, summa , stirling
429
cdef int i,j ,N ,m,M,k
430
R2=R*R
431
d_c_i=(<double complex>_Complex_I)
432
z=iR+x
433
y=R
434
iR=d_c_i*R
435
N=10
436
Nr=<double> N # d_ten
437
u=Nr+x
438
v=y
439
w=iR+u
440
w2=w*w #d_100-R*R+d_20*iR #w*w
441
summa=c_zero
442
ww=c_one/w
443
#ns=50
444
for i from 1 <=i <num_ber:
445
tmp=(<double complex >Ber[i])*ww
446
summa=summa+tmp
447
if( cabs(tmp) < prec):
448
break
449
ww=ww/(w2)
450
a=cabs(w) #d_100+R2 # cabs(w) # sqrt(u*u+y*y)
451
lnw=log(a)
452
argw=carg(w)
453
Res=(u-d_half)*lnw-R*argw-u+ln2PI2
454
Ims=R*(lnw-d_one)+(u-d_half)*argw
455
stirling=<double complex>Res+(<double complex>Ims)*d_c_i
456
# this was really for GAMMA(z+N)
457
res=stirling+summa
458
for j from 0 <=j<=N-1:
459
cr=<double complex> j
460
tmp=iR+cr+d_one
461
res=res-clog(tmp)
462
return res
463
464
465
466
467