我需要使用泰勒级数在没有 math.h 库的情况下编写自己的 asin() 函数。它适用于 <-0.98;0.98> 之间的数字,但当我接近极限时,它会停止 1604 次迭代,因此不准确。
我不知道如何让它更准确。非常感谢任何建议!
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define EPS 0.000000000001
double my_arcsin(double x)
{
long double a, an, b, bn;
a = an = 1.0;
b = bn = 2.0;
long double n = 3.0;
double xn;
double xs = x;
double xp = x;
int iterace = 0;
xn = xs + (a/b) * (my_pow(xp,n) / n);
while (my_abs(xn - xs) >= EPS)
{
n += 2.0;
an += 2.0;
bn += 2.0;
a = a * an;
b = b * bn;
xs = xn;
xn = xs + (a/b) * (my_pow(xp,n) / n);
iterace++;
}
//printf("%d\n", iterace);
return xn;
}
int main(int argc, char* argv[])
{
double x = 0.0;
if (argc > 2)
x = strtod(argv[2], NULL);
if (strcmp(argv[1], "--asin") == 0)
{
if (x < -1 || x > 1)
printf("nan\n");
else
{
printf("%.10e\n", my_arcsin(x));
//printf("%.10e\n", asin(x));
}
return 0;
}
}
还有我的值(value)观和期望值的简短列表:
My values Expected values my_asin(x)
5.2359877560e-01 5.2359877560e-01 0.5
1.5567132089e+00 1.5707963268e+00 1 //problem
1.4292568534e+00 1.4292568535e+00 0.99 //problem
1.1197695150e+00 1.1197695150e+00 0.9
1.2532358975e+00 1.2532358975e+00 0.95
即使您使用的级数展开式的收敛半径为 1,因此级数最终会收敛到 -1 < x < 1,但在接近该区间的极限时收敛速度确实慢得令人痛苦。解决方案是以某种方式避免间隔的这些部分。
我建议你
- 对|x| 使用您的原始算法<= 1/sqrt(2),
- 使用恒等式 arcsin(x) = pi/2 - arcsin(sqrt(1-x^2)) for 1/sqrt(2) < x <= 1.0,
- 对 -1.0 <= x < -1/sqrt(2) 使用恒等式 arcsin(x) = -pi/2 + arcsin(sqrt(1-x^2))。
通过这种方式,您可以将输入 x 转换为 [-1/sqrt(2),1/sqrt(2)],收敛速度相对较快。
我是一名优秀的程序员,十分优秀!