将cos和sin存储到向量中并获得奇怪的值

use*_*774 1 c++ floating-point

我的代码

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";
}
Run Code Online (Sandbox Code Playgroud)

我希望输出

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

正如你所看到的,我得到的是这些奇怪的值,而不是零.有人可以解释为什么会这样吗?

Pas*_*uoq 10

6.12303e-17举个例子,代表值6.12303*10 -17,或0.00000000000000000612303.

你得到这个值的原因是你没有申请cosπ/ 2,这double无论如何都不能表示(它是无理的).该cos函数应用于double接近π/ 2,通过将90乘以M_PI并除以180得到.由于参数不是π/ 2,结果不必为0.实际上,因为浮点数更多密集接近于零,对于任何浮点格式来说,将正确舍入cos到任何浮点数的结果都非常不可能产生零结果.

事实上,由于cosπ/ 2 的导数是-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作为结果cos(M_PI).不同之处在于有许多浮点数,有些非常小,大约为0,这些可以非常精确地表示预期的非零结果.相比之下,0.5并且-1.0只有少数邻居,并且对于足够接近π/ 3和π的输入,数字0.5-1.0最终作为最接近的可表示的双精度值返回到相应的数学结果(不是1/2)或-1,因为输入不是π/ 3或π).

解决问题的最简单方法是使用假设函数cosdeg,sindeg直接计算角度的余弦和正弦度.由于60和90可以完全表示为双精度浮点数,因此这些函数没有理由不返回0.5或0.0(也可以精确表示为双精度浮点数).我之前提出了一个与这些函数有关的问题,但没有人指出任何已经可用的实现.

的功能sinpicospi通过njuffa指出通常可用的,并且它们允许以计算正弦和余弦或π/ 2,π/ 4或甚至7.5*π,但不是π/ 3的,自号1/3他们将有要应用于二进制浮点不能完全表示.