计算 pi 时 asin() 问题

Issue with asin() while calculating pi

我正在尝试自学来自 python/java 的 C(我认为是 C99?gcc 8.1.0)。我正在研究的练习题之一是如何计算 pi 到给定的小数。

我目前正在使用以下等式 2 * (Arcsin(sqrt(1 - 0.5^2)) + abs(Arcsin(0.5))).

float pi_find(float nth)
{
    float x, y, z;

    /* Equation = 2 * (Arcsin(sqrt(1 - x^2)) + abs(Arcsin(x))) [x|-1<=x=>1, xeR]*/
    x = sqrt(1-pow(nth, 2)); /* Carrot (^) notation does not work, use pow() */
    y = fabs(asin(nth)); /* abs is apparently int only, use fabs for floats */
    z = x+y;
    printf("x: %f\ny: %f\nsum: %f\n", x, y, (x+y));
    printf("%f\n", asin(z));
    return 2 * asin(z); /* <- Error Happens */
}
int main()
{
  float nth = 0.5f;

  double pi = pi_find(nth);

  printf("Pi: %f\n", pi);

  return 0;
}

结果:

x: 0.866025
y:0.523599
sum: 1.389624
z:-1.#IND00
Pi:-1.#IND00

我知道问题在于添加 x + y 总和为 1.389...而 asin() 只能处理 -1 和 +1 之间的值。

然而!

我在 python 旁边使用 Wolfram Alpha 检查每一步的计算是否正确,它可以计算 asin(1.389...)。 [1]

我不懂虚数,这远远超出了我作为数学家的能力,但下面是 Wolfram 正在做的事情。 [2]

1.570796 -0.8563436 i
Interpreting as: 0.8563436 i
Assuming multiplication | Use a list instead
Assuming i is the imaginary unit | Use i as a variable instead

在写这篇文章时,我发现了 C99 中添加的 _Imaginary 数据类型,但我不太明白它是否与 Wolfram 所做的相同。

也查了一下虚数是怎么算的,但是我不太明白'The square roots of a negative number cannot be distinguished until one of the two is defined as the imaginary unit'是怎么算的。 [3]

有人可以帮我解决这个问题吗? 明明是知识问题,不是数学或语言限制

p.s 是的,我知道这是垃圾代码,在我正确重写它之前,我使用了一种奇怪的调试方式。

[1]:Wolfram_Alpha Calculation [2]:Wolfram_Alpha Assumption [3]:Imaginary Numbers

问题是您对表达式的分组不正确。所需的表达式是:

2 * (Arcsin(sqrt(1 - 0.5^2)) + abs(Arcsin(0.5)))

用第 n 个代替 0.5,这变成:

2 * (Arcsin(sqrt(1 - nth^2)) + abs(Arcsin(nth))).

特别是,第一个 Arcsin 的参数是 sqrt(1 - nth^2)),第二个 Arcsin 的参数是 nth。

您最好还是使用 nth * nth 而不是 pow(nth, 2)。它既更快又更准确。

所以你想要的是:

x = asin(sqrt(1 - nth*nth));
y = fabs(asin(nth));
r = 2*(x + y);

注意 asin 的参数 永远不会 有大于 1 的量级(只要 nth 小于 1)。

此外,正如我之前在评论中提到的,您应该将所有 float 变量更改为 double。无论如何,您正在使用双精度数学库函数,因此没有理由通过将结果存储在 float 变量中来丢弃一半的精度。

在 C 语言中,floatdouble 类型为“实”数建模,我假设您已经掌握了。

在数学中,"complex" numbers是实数的扩充。每个实数都算作复数,但“虚数”也是如此,您可以通过将实数乘以“虚数单位”(在数学符号中标记为i,通常描述为“平方”来得到-1 的根").

从数学上讲,基本算术运算(+-*/)是在复数上定义的。事实证明,您也可以扩展反正弦等函数来对复数进行运算。

无需进一步了解细节,Wolfram Alpha 几乎肯定会为您提供来自反正弦的复数版本的值。

然而,标准 C 函数 asin() 是未扩展版本:它接受一个 double 作为参数,并且 returns 一个 double 作为结果.由于 double 仅对实数建模,因此 asin() 对于 [-1,1].

之外的输入值没有意义