我需要用泰勒级数编写自己的asin()函数,不需要math.h库。它对之间的数字很好,但当我接近极限时,它会以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;
}
}
以及我的价值观和期望值的简短列表:
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
最佳答案
请注意:在这种情况下,我强烈推荐@Bence的方法,因为您不能期望一个数据精度低的缓慢收敛的方法获得任意精度。
不过,我愿意向您展示如何使用当前算法改进结果。
主要的问题是a
和b
增长太快,很快就会变成inf
(仅在大约150次迭代之后)。另一个类似的问题是当my_pow(xp,n)
增长时n
增长很快,但是在这种情况下这并不重要,因为我们可以假设输入数据在[-1, 1]
的范围内。
因此,我刚刚通过引入a/b
更改了您处理ab_ratio
的方法,请参见我编辑的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define EPS 0.000000000001
#include <math.h>
#define my_pow powl
#define my_abs fabsl
double my_arcsin(double x)
{
#if 0
long double a, an, b, bn;
a = an = 1.0;
b = bn = 2.0;
#endif
unsigned long _n = 0;
long double ab_ratio = 0.5;
long double n = 3.0;
long double xn;
long double xs = x;
long double xp = x;
int iterace = 0;
xn = xs + ab_ratio * (my_pow(xp,n) / n);
long double step = EPS;
#if 0
while (my_abs(step) >= EPS)
#else
while (1) /* manually stop it */
#endif
{
n += 2.0;
#if 0
an += 2.0;
bn += 2.0;
a = a * an;
b = b * bn;
#endif
_n += 1;
ab_ratio *= (1.0 + 2.0 * _n) / (2.0 + 2.0 * _n);
xs = xn;
step = ab_ratio * (my_pow(xp,n) / n);
xn = xs + step;
iterace++;
if (_n % 10000000 == 0)
printf("%lu %.10g %g %g %g %g\n", _n, (double)xn, (double)ab_ratio, (double)step, (double)xn, (double)my_pow(xp, n));
}
//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;
}
}
对于
0.99
(甚至0.9999999
)它很快就会给出10个以上有效数字的正确结果。但是,当接近1
时,速度会变慢。实际上,这个过程在我的笔记本电脑上已经运行了将近12分钟,在迭代之后,当前的结果是
--asin 1
。更新:现在已经1h51min了,结果
1.570786871
,迭代次数3560000000
。关于c - 自己的asin()函数(使用Taylor系列)不准确,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20196000/