来自 cmath 库的 asin() 函数 returns 不准确的值

The asin() function from cmath library returns inaccurate values

我正在使用 asinacos 函数从 cmath 库中找到与相应的 sinecosine 值的角度,但有时 returns 值不准确。例如下面代码的结果不为零:

cout << acos(-1) / 6 - asin(0.5) << endl;

那我该怎么办?我使用 acos(-1) 作为 Pi 的值,然后在我的代码中某处我想查看例如有多少 asin(0.5)在 Pi 中有,但当前方法不起作用。

在询问了专家之后,我了解到问题出在浮点数在计算机中的存储方式上。 没有确切的解决方案,但是我在这里使用下面的方法来忽略值的不准确性:

if (asin(0.5) - (acos(-1) / 6) < 10e-10) {
    cout << "equal" << endl;
}
  • 不精确潜伏在各个地方。

double 通常使用基数 2 进行编码,例如 binary64. As a floating point number, it can be expected to be a Dyadic rational。关键是有限浮点数是有理数.

在数学上,arccos(-1) 是 π。 π是一个无理数。即使有很多位精度,double 也不能 准确地表示 π。取而代之的是 acos(-1) 附近的值被称为 machine pi 或者 M_PI.

在数学上,arcsin(0.5) 是 π/6。如上,asin(0.5) 是 π/6 附近的值。

除以 3 会引入潜在的不精确性。每个 double/3 中的大约 2 个导致不精确但四舍五入的商。

  • 当然不是零。

奇怪的是 acos(-1) / 3 - asin(0.5) 大约是 1.57...,而不是 0.0。

我怀疑 OP 正在研究 acos(-1) / 6 - asin(0.5)

这里减去附近的值会导致 catastrophic cancellation 并且一个小的但非零的差异是可能的结果。


So what can I do?
I want to see for example how many asin(0.5) are there in Pi

容忍计算中的边际误差并采用所需的舍入。

double my_pi = acos(-1);
double target = asin(0.5);
long close_integer_quotient = lround(my_pi/target);