将cos和sin存储到向量中,得到奇怪的值 [英] Storing cos and sin into a vector and getting weird values

查看:127
本文介绍了将cos和sin存储到向量中,得到奇怪的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的代码

  double to_radians(double theta)
{
return(M_PI * theta) / 180.0;
}

int main()
{
std :: vector< std :: pair< double,double>>点数;
for(double theta = 0.0; theta <= 360.0; theta + = 30.0)
{
points.push_back(std :: make_pair(std :: cos(to_radians ,std :: sin(to_radians(theta))));
}
for(auto point:points)
std :: cout<< point.first<< < point.second<< \\\
;
}

我期望输出

 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

得到这些奇怪的值而不是零。

解决方案

6.12303e-17 ,以一个示例,表示值6.12303 * 10 -17 或0.00000000000000000612303。



您获得此值作为结果的原因是你没有应用 cos 到π/ 2,这不能表示为 double 反正(它是不合理的)。 cos 函数应用于接近π/ 2的 double ,通过将90乘以 M_PI 并除以180.由于参数不是π/ 2,结果不必为0.实际上,由于浮点数在零附近更加密集,因此极不可能对于任何浮点格式,应用正确舍入的 cos 到任何浮点数的结果都是零。



<实际上,由于π/ 2中的 cos 的导数为-1,所以对于表达式 cos(M_PI / 2.0) M_PI / 2 和π/ 2之间的差的近似值。因为双精度IEEE 754格式只能表示任意数字的前16个第一个十进制数字,所以这个差异确实是d * 10 -17 的顺序。






请注意,相同的参数适用于获取 0.5 作为<$ c作为 cos(M_PI)的结果的$ c> cos(M_PI / 3.0),或甚至 -1.0 code>。不同之处在于有很多浮点数,一些非常小,大约为0,并且这些可以非常精确地表示预期的非零结果。相比之下, 0.5 -1.0 只有几个邻居,对于接近π/ 3和π ,数字 0.5 -1.0 最终作为最近的可表示双精度值返回到相应的数学结果(不是1/2或-1,因为输入不是π/ 3或π)。



您的问题的最简单的解决方案是使用假设函数 cosdeg sindeg 将直接计算角度的余弦和正弦。由于60和90完全可以表示为双精度浮点数,因此这些函数没有借口不返回0.5或0.0(也可精确表示为双精度浮点数)。我曾问过与这些功能相关的问题但没有人指向任何已有的实现。



函数 sinpi cospi由njuffa指出的通常可用,并且它们允许计算正弦和余弦或π/ 2,π/ 4或甚至7.5 *π,而不是π/ 3, 3,它们必须应用于不能精确地在二进制浮点中表示。


My code

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";
}

Output I expect

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

Output I get:

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

As you can see I am getting these strange values instead of zero. Can somebody explain why this is happening?

解决方案

6.12303e-17, to take an example, represents the value 6.12303*10-17, or 0.00000000000000000612303.

The reason you obtain this value as result is that you did not apply cos to π/2, which is not representable as a double anyway (it's irrational). The cos function was applied to a double close to π/2, obtained by multiplying 90 by M_PI and dividing by 180. Since the argument is not π/2, the result does not have to be 0. In fact, since floating-point numbers are more dense near zero, it is extremely unlikely for any floating-point format that applying a correctly rounded cos to any floating-point number produces exactly zero as result.

In fact, since the derivative of cos in π/2 is -1, the value obtained for the expression cos(M_PI/2.0) is a close approximation of the difference between M_PI/2 and π/2. That difference is indeed of the order of d*10-17, since the double-precision IEEE 754 format can only represent the first 16 or so first decimal digits of an arbitrary number.


Note that the same argument applies to obtaining 0.5 as the result of cos(M_PI/3.0), or even -1.0 as the result of cos(M_PI). The difference is that there are many floating-point numbers, some very small, around 0, and these can represent very precisely the intended non-zero result. In comparison, 0.5 and -1.0 have only a few neighbors, and for inputs close enough to π/3 and π, the numbers 0.5 and -1.0 end up being returned as the nearest representable double-precision value to the respective mathematical result (which isn't 1/2 or -1, since the input is not π/3 or π).

The simplest solution to your problem would be to use hypothetical functions cosdeg and sindeg that would compute directly the cosine and sine of angles in degrees. Since 60 and 90 are representable exactly as double-precision floating-point numbers, these functions would have no excuse not to return 0.5 or 0.0 (also exactly representable as double-precision floating-point numbers). I asked a question in relation to these functions earlier but no-one pointed to any already available implementation.

The functions sinpi and cospi pointed out by njuffa are often available, and they allow to compute the sine and cosine or π/2, π/4 or even 7.5*π, but not of π/3, since the number 1/3 they would have to be applied to is not representable exactly in binary floating-point.

这篇关于将cos和sin存储到向量中,得到奇怪的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆