C Own asin()函数(带泰勒级数)不精确

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

我需要使用泰勒级数编写自己的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;
    }
}

即使您使用的级数展开的收敛半径为1,因此级数最终将收敛到-1 我建议你


  • 使用| x |的原始算法,即使您使用的级数展开的收敛半径为1,因此级数最终将收敛到-1 我建议你


    • 请注意:在这种情况下,我强烈推荐@Bence的方法,因为你不能指望低数据精度的缓慢收敛方法获得任意精度

      但是,我愿意向您展示如何使用您当前的算法改进结果

      主要问题是
      a
      b
      增长太快,很快就会变成
      inf
      (仅经过大约150次迭代)。另一个类似的问题是
      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
      (甚至
      0.9999999
      ),它很快会给出超过10个有效数字的正确结果。但是,当接近
      1

      实际上,这个过程在我的笔记本电脑上运行了将近12分钟,计算
      --asin 1
      ,经过
      3560000000
      次迭代后,当前结果是
      1.570786871


      更新:现在已经1h51min了,结果是
      1.570792915
      ,迭代次数是
      273400000000
      请注意:在这种情况下,我强烈推荐@Bence的方法,因为你不能期望一个低数据精度的缓慢收敛的方法来获得任意精度

      但是,我愿意向您展示如何使用您当前的算法改进结果

      主要问题是
      a
      b
      增长太快,很快就会变成
      inf
      (仅经过大约150次迭代)。另一个类似的问题是
      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)<