我的代码
double to_radians(double theta)
{
return (M_PI * theta) / 180.0;
}
int main()
{
std::vector<std::pair<double, double>> points;
for (double theta = 0.0; theta <= 360.0; theta += 30.0)
{
points.push_back(std::make_pair(std::cos(to_radians(theta)), std::sin(to_radians(theta))));
}
for (auto point : points)
std::cout << point.first << " " << point.second << "\n";
}
我希望输出
1 0 0.866025 0.5 0.5 0.866025 0 1 -0.5 0.866025 -0.866025 0.5 -1 0 -0.866025 -0.5 -0.5 -0.866025 0 -1 0.5 -0.866025 0.866025 -0.5 1 0
输出我得到:
1 0 0.866025 0.5 0.5 0.866025 6.12303e-17 1 -0.5 0.866025 -0.866025 0.5 -1 1.22461e-16 -0.866025 -0.5 -0.5 -0.866025 -1.83691e-16 -1 0.5 -0.866025 0.866025 -0.5 1 -2.44921e-16
正如你所看到的,我得到的是这些奇怪的值,而不是零。有人可以解释为什么会这样吗?
答案 0 :(得分:10)
6.12303e-17
表示值6.12303 * 10 -17 或0.00000000000000000612303。
您获得此值的原因是您没有将cos
应用于π/ 2,这无论如何都不能表示为double
(这是不合理的)。 cos
函数应用于接近π/ 2的double
,通过将90乘以M_PI
并除以180得到。由于参数不是π/ 2,结果不会事实上,由于浮点数在零附近更密集,因此对于任何浮点格式来说,将正确舍入的cos
应用于任何浮点数的结果几乎不会产生零结果
事实上,由于π/ 2中cos
的导数为-1,因此表达式cos(M_PI/2.0)
获得的值与M_PI/2
和π/之间的差值非常近似。 2。这个差异确实是d * 10 -17 的顺序,因为双精度IEEE 754格式只能代表任意数字的前16个左右第一个十进制数字。
请注意,相同的参数适用于0.5
的结果,cos(M_PI/3.0)
或-1.0
的{{1}}结果。不同之处在于有许多浮点数,有些非常小,大约为0,这些可以非常精确地表示预期的非零结果。相比之下,cos(M_PI)
和0.5
只有几个邻居,而对于足够接近π/ 3和π的输入,数字-1.0
和0.5
最终会被返回为相应数学结果的最近可表示的双精度值(不是1/2或-1,因为输入不是π/ 3或π)。
对您的问题最简单的解决方案是使用假设函数-1.0
和cosdeg
来直接计算角度的余弦和正弦度。由于60和90可以完全表示为双精度浮点数,因此这些函数没有理由不返回0.5或0.0(也可以精确表示为双精度浮点数)。我之前问过a question in relation to these functions,但没有人指出任何已经可用的实现。
njuffa指出的函数sindeg
和sinpi
通常是可用的,它们允许计算正弦和余弦或π/ 2,π/ 4甚至7.5 *π,但不能π/ 3,因为它们必须应用的数字1/3不能完全用二进制浮点表示。
答案 1 :(得分:0)
这是一个浮点舍入错误。 Trig函数实现为数学序列,它们在计算级别上近似,导致数字非常接近零,例如6.12303e-17
而不是预期的0
。