来自 cmath 库的 asin() 函数 returns 不准确的值
The asin() function from cmath library returns inaccurate values
我正在使用 asin 和 acos 函数从 cmath 库中找到与相应的 sine 和 cosine 值的角度,但有时 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);
我正在使用 asin 和 acos 函数从 cmath 库中找到与相应的 sine 和 cosine 值的角度,但有时 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);