#include <math.h>
#include "complex.h"
#define EPS 6.0e-8
#define EULER 0.57721566
#define MAXIT 100
#define PIBY2 1.5707963 π / 2.
#define FPMIN 1.0e-30
#define TMIN 2.0
#define TRUE 1
#define ONE Complex(1.0, 0.0)
void cisi(float x, float * ci, float * si) {
void nrerror(char error_text[]);
int i, k, odd;
float a, err, fact, sign, sum, sumc, sums, t, term;
fcomplex h, b, c, d, del;
t = fabs(x);
if (t == 0.0) {
* si = 0.0;
* ci = -1.0 / FPMIN;
return;
}
if (t > TMIN) {
b = Complex(1.0, t);
c = Complex(1.0 / FPMIN, 0.0);
d = h = Cdiv(ONE, b);
for (i = 2; i <= MAXIT; i++) {
a = -(i - 1) * (i - 1);
b = Cadd(b, Complex(2.0, 0.0));
d = Cdiv(ONE, Cadd(RCmul(a, d), b));
c = Cadd(b, Cdiv(Complex(a, 0.0), c));
del = Cmul(c, d);
h = Cmul(h, del);
if (fabs(del.r - 1.0) + fabs(del.i) < EPS) break;
}
if (i > MAXIT) nrerror("cf failed in cisi");
h = Cmul(Complex(cos(t), -sin(t)), h);
* ci = -h.r;
* si = PIBY2 + h.i;
} else {
if (t < sqrt(FPMIN)) {
sumc = 0.0;
sums = t;
} else {
sum = sums = sumc = 0.0;
sign = fact = 1.0;
odd = TRUE;
for (k = 1; k <= MAXIT; k++) {
fact *= t / k;
term = fact / k;
sum += sign * term;
err = term / fabs(sum);
if (odd) {
sign = -sign;
sums = sum;
sum = sumc;
} else {
sumc = sum;
sum = sums;
}
if (err < EPS) break;
odd = !odd;
}
if (k > MAXIT) nrerror("maxits exceeded in cisi");
}
* si = sums;
* ci = sumc + log(t) + EULER;
}
if (x < 0.0) * si = -( * si);
}
道森积分
道森积分 F(x) 定义为
F(x)=e−x2∫0xet2dt
该函数还可以通过以下方式与复杂的误差函数相关:
F(z)=2iπe−z2[1−erfc(−iz)]
F(z) 的一个显着近似是
F(z)=limh→0π1∑n odd ne−(z−nh)2
上面等式的不同寻常之处在于,随着 h 变小,其精度呈指数级增长,因此相当适中的 h 值(以及相应的级数相当快的收敛)给出了非常准确的近似值。首先方便的是移动求和索引以将其大约集中在指数项的最大值上。定义 n0 为最接近 x / h 的偶数,且 x0≡n0h、x′≡x−x0和 n′≡n−n0,于是
F(x)≈π1∑n′=−Nn′ odd Nn′+n0e−(x′−n′h)2
其中,当 h 足够小且 N 足够大时,近似等式是准确的。如果我们注意到这一点,这个公式的计算可以大大加快