C Own asin()函数(带泰勒级数)不精确
我需要使用泰勒级数编写自己的asin()函数,而不使用math.h库。它适用于介于之间的数字,但当我接近极限时,它会停止1604次迭代,因此是不准确的 我不知道如何使它更准确。非常感谢您的任何建议 代码如下:C Own asin()函数(带泰勒级数)不精确,c,taylor-series,C,Taylor Series,我需要使用泰勒级数编写自己的asin()函数,而不使用math.h库。它适用于介于之间的数字,但当我接近极限时,它会停止1604次迭代,因此是不准确的 我不知道如何使它更准确。非常感谢您的任何建议 代码如下: #include <stdio.h> #include <stdlib.h> #include <string.h> #define EPS 0.000000000001 double my_arcsin(double x) { long d
#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;
}
}
即使您使用的级数展开的收敛半径为1,因此级数最终将收敛到-1
- 使用| x |的原始算法,即使您使用的级数展开的收敛半径为1,因此级数最终将收敛到-1
我建议你 - 请注意:在这种情况下,我强烈推荐@Bence的方法,因为你不能指望低数据精度的缓慢收敛方法获得任意精度
但是,我愿意向您展示如何使用您当前的算法改进结果
主要问题是
和a
增长太快,很快就会变成b
(仅经过大约150次迭代)。另一个类似的问题是inf
在my_pow(xp,n)
增长时增长很快,但是在这种情况下这并不重要,因为我们可以假设输入数据在n
的范围内 因此,我刚刚通过引入[-1,1]
更改了您处理ab_比率
的方法,请参见我编辑的代码:a/b
#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; } }
对于#包括 #包括 #包括 #定义EPS 0.000000000001 #包括 #定义我的力量 #定义我的abs fabsl 双倍my_Arcin(双倍x) { #如果0 长双a,an,b,bn; a=an=1.0; b=bn=2.0; #恩迪夫 无符号长=0; 长双ab_比=0.5; 长双n=3.0; 长双xn; 长双xs=x; 长双xp=x; int-iterace=0; xn=xs+ab_比率*(我的功率(xp,n)/n); 长双台阶=EPS; #如果0 while(my_abs(step)>=EPS) #否则 而(1)/*手动停止*/ #恩迪夫 { n+=2.0; #如果0 an+=2.0; bn+=2.0; a=a*an; b=b*bn; #恩迪夫 _n+=1; ab_比率*=(1.0+2.0*_n)/(2.0+2.0*_n); xs=xn; 阶跃=ab_比率*(我的功率(xp,n)/n); xn=xs+阶跃; iterace++; 如果(\n%10000000==0) printf(“%lu%.10g%g%g%g%g%g\n”),_n,(double)xn,(double)ab_比率,(double)阶跃,(double)xn,(double)my_pow(xp,n)); } //printf(“%d\n”,iterace); 返回xn; } int main(int argc,char*argv[]) { 双x=0.0; 如果(argc>2) x=strtod(argv[2],NULL); if(strcmp(argv[1],“--asin”)==0) { 如果(x<-1 | | x>1) printf(“nan\n”); 其他的 { printf(“%.10e\n”,my_arcin(x)); //printf(“%.10e\n”,asin(x)); } 返回0; } }
(甚至0.99
),它很快会给出超过10个有效数字的正确结果。但是,当接近0.9999999
1
实际上,这个过程在我的笔记本电脑上运行了将近12分钟,计算
,经过--asin 1
次迭代后,当前结果是3560000000
1.570786871
更新:现在已经1h51min了,结果是
,迭代次数是1.570792915
,请注意:在这种情况下,我强烈推荐@Bence的方法,因为你不能期望一个低数据精度的缓慢收敛的方法来获得任意精度 但是,我愿意向您展示如何使用您当前的算法改进结果 主要问题是273400000000
和a
增长太快,很快就会变成b
(仅经过大约150次迭代)。另一个类似的问题是inf
在my_pow(xp,n)
增长时增长很快,但是在这种情况下这并不重要,因为我们可以假设输入数据在n
的范围内 因此,我刚刚通过引入[-1,1]
更改了您处理ab_比率
的方法,请参见我编辑的代码:a/b
#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; } }
#包括 #包括 #包括 #定义EPS 0.000000000001 #包括 #定义我的力量 #定义我的abs fabsl 双倍my_Arcin(双倍x) { #如果0 长双a,an,b,bn; a=an=1.0; b=bn=2.0; #恩迪夫 无符号长=0; 长双ab_比=0.5; 长双n=3.0; 长双xn; 长双xs=x; 长双xp=x; int-iterace=0; xn=xs+ab_比率*(我的功率(xp,n)/n); 长双台阶=EPS; #如果0 while(my_abs(step)>=EPS) #否则 而(1)/*手动停止*/ #恩迪夫 { n+=2.0; #如果0 an+=2.0; bn+=2.0; a=a*an; b=b*bn; #恩迪夫 _n+=1; ab_比率*=(1.0+2.0*_n)/(2.0+2.0*_n); xs=xn; 阶跃=ab_比率*(我的功率(xp,n)/n); xn=xs+阶跃; iterace++; 如果(\n%10000000==0) printf(“%lu%.10g%g%g%g%g%g\n”),_n,(double)xn,(double)ab_比率,(double)阶跃,(double)xn,(double)my_pow(xp,n)); } //printf(“%d\n”,iterace); 返回xn; } int main(int argc,char*argv[]) { 双x=0.0; 如果(argc>2) x=strtod(argv[2],NULL); if(strcmp(argv[1],“--asin”)==0) { if(x)<
- 请注意:在这种情况下,我强烈推荐@Bence的方法,因为你不能指望低数据精度的缓慢收敛方法获得任意精度
但是,我愿意向您展示如何使用您当前的算法改进结果
主要问题是