-1

我正在为 arctan(x) 使用 Maclaurin 系列,但我没有得到正确的答案。我正在以弧度进行计算。这是到目前为止的功能:

fp32 t32rArcTangent(fp32 number)
{
fp32 a, b, c, d;    /* Temp Variables */
fp32 t;             /* Number Temp */
uint32 i;           /* Loop Counter */

/* Time Savers */
if (b32fpcomp(number, MM_FP8INFINITY)) return((fp32)MM_PI / 2);
if (b32fpcomp(number, -MM_FP8INFINITY)) return(-(fp32)MM_PI / 2);

/* Setup */
a = 0;
b = 0;
c = 1;
d = number;
t = number * number;

/* Calculation Loop */
for (i = 0; i < MMPRVT_FP32_TRIG_LIMIT; i++)
  {
    b += d;
    if (b32fpcomp(a, b)) break;
    a = b;
    c += 2;
    d *= -1 * t / c;
  }
#ifdef DEBUG
printf("Loops: %lu\n", i);
#endif

/* Result */
return(a);

fp32 = typedef'd float

uint32 = typedef'd unsigned long int

MM_FP8INFINITY 是 fp32 数据类型可以包含的最大数字。

MM_PI 只是大约 50 位的 PI。

MMPRVT_FP32_TRIG_LIMIT 是可用于计算结果的最大循环数。这是为了防止级数展开进入无限循环,如果由于某种原因级数未能收敛。

这些是我得到的结果:

Testing arctangent(x) function.
Loops: 0
arctan(0):      0
Loops: 8
arctan(1):      0.724778414
Loops: 13
arctan(R3):     0.709577262
Loops: 6
arctan(1/R3):   0.517280579

R3 只是 3 的平方根,即 1.732050808....

现在我知道arctan级数的收敛半径是|x| <= 1,所以我想我必须以某种方式减少输入。问题是对于 arctan,函数的域是 (-INF, +INF)。那么如何减少呢?这是按弧度角计算的。


感谢您指出了这一点。问题已得到纠正,我也完成了输入减少。这是已完成且已更正的函数,它现在给出了正确的答案:

fp32 t32rArcTangent(fp32 number)
{
fp32 a, b, c, d;    /* Temp Variables */
fp32 t;             /* Number Temp */
uint32 i;           /* Loop Counter */
uint8 fr;           /* Reduction Flag */

/* Time Savers */
if (b32isInf(number) == -1) return(-(fp32)MM_PI / 2);
if (b32isInf(number) == 1) return((fp32)MM_PI / 2);
if (b32isNaN(number)) return(number);
if (b32fpcomp(number, MM_FP8INFINITY)) return((fp32)MM_PI / 2);
if (b32fpcomp(number, -MM_FP8INFINITY)) return(-(fp32)MM_PI / 2);
if (b32fpcomp(number, ONE)) return((fp32)MM_PI / 4);
if (b32fpcomp(number, -ONE)) return(-(fp32)MM_PI / 4);

/* Reduce Input */
if (number > ONE)
    {
      number = 1 / number;
      fr = 1;
    }
  else fr = 0;

/* Setup */
a = 0;
b = 0;
c = 1;
d = number;
t = number * number;

/* Calculation Loop */
for (i = 0; i < MMPRVT_FP32_TRIG_LIMIT; i++)
  {
    b += d / c;
    if (b32fpcomp(a, b)) break;
    a = b;
    c += 2;
    d *= -1 * t;
    #ifdef DEBUG
    printf("a=%g b=%g, c=%g d=%g\n", a, b, c, d);
    #endif
  }
#ifdef DEBUG
printf("Loops: %lu\n", i);
#endif

/* Result */
if (fr != 0) a = ((fp32)MM_PI / 2) - a;
return(a);
}
4

1 回答 1

5

考虑除以 后每个循环中的项会发生什么变化c

c += 2;
d *= -1 * t / c;

首先你要除以 1 [隐含地,在此之前],然后除以 3,然后再除以 5,这听起来不错,但是因为你将 d 乘以这个术语,所以你实际上是除以每个除数。IOW,而不是

x - 1/3*x^3 + 1/5*x^5 - 1/7*x^7 + 1/9*x^9

你想要的,你正在计算

x - 1/(1*3)*x^3 + 1/(1*3*5)*x^5 - 1/(1*3*5*7)*x^7 + 1/(1*3*5*7*9)*x^9

你仍然可以使用你的d *= -t技巧,但你应该移动分区。

于 2012-06-17T01:46:06.903 回答