数学.Cos & C# 中的 Math.Sin
我正在尝试一些我认为应该相当简单的事情。我有一个角度、一个位置和一个距离,我想从这些信息中找到 X、Y 坐标。
以 90 度的示例输入为例,我使用以下代码将值转换为弧度:
public double DegreeToRadian(float angle)
{
return Math.PI * angle / 180.0;
}
这给了我 1.5707963267949 弧度 然后,当我使用时
Math.Cos(radians)
,我最终得到的答案是:6.12303176911189E-17
到底发生了什么? 90 度的余弦应该是 0,那么为什么我会出现这样的偏差......更重要的是我怎样才能阻止它?
I'm trying something that I thought should be reasonably simple. I have an angle, a position and a distance and I want to find the X,Y co-ordinates from this information.
With an example input of 90 degrees I convert the value to radians with the following code:
public double DegreeToRadian(float angle)
{
return Math.PI * angle / 180.0;
}
This gives me 1.5707963267949 radians
Then when I use
Math.Cos(radians)
I end up with an an answer of: 6.12303176911189E-17
What the heck is going on? The cosine of 90 degrees should be 0, so why am I getting such a deviance... and more importantly how can I stop it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
让我用另一个问题来回答你的问题:你认为 6.12303176911189E-17 距离 0 有多远?您所说的偏差实际上是由于浮点数的内部存储方式造成的。我建议您阅读以下文章。在 .NET 中,它们使用 IEEE 754 标准存储。
Let me answer your question with another one: How far do you think 6.12303176911189E-17 is from 0? What you call deviance is actually due to the way floating point numbers are internally stored. I would recommend you reading the following article. In .NET they are stored using the IEEE 754 standard.
请参阅上面的答案。请记住,6.12303176911189E-17 是 0.00000000000000006(我什至可能漏掉了一个零!),所以这是一个非常非常小的偏差。
See answers above. Remember that 6.12303176911189E-17 is 0.00000000000000006 (I may have even missed a zero there!) so it is a very, very small deviation.
您应该使用舍入,
结果将是:
罪恶:1
因数:0
you should use rounding
the result would be:
sin: 1
cos: 0
阅读浮点运算。它从来都不是、也不可能是准确的。切勿与任何内容进行精确比较,而是检查数字是否存在(小)epsilon 差异。
Read up on floating point arithmetic. It is never and can never be exact. Never compare exactly to anything, but check whether the numbers differ by a (small) epsilon.
其他帖子关于使用浮点实现的实际问题是正确的,该实现返回带有小错误的结果。但是,如果浮点库实现能够保留众所周知函数的基本标识,那就太好了:
Math.Sin(Math.PI)
should 等于0 ,
Math.Cos(Math.PI)
应该等于-1
,Math.Sin(Math.PI/2)
应该等于1
,Math.Cos(Math.PI/2)
应该等于0
等您会期望浮点库会尊重这些和其他三角恒等式,无论其常数值有多大误差(例如数学.PI)。
事实上,您从
Math.Cos(Math.PI/2)
中收到一个小错误,这表明该实现正在计算结果,而不是从表中提取结果。更好地实现 Math.Cos 和其他超越函数对于特定的身份可能会更准确。我确信就 C# 而言,这种行为是预期的,因此 Microsoft 无法在不影响现有代码的情况下更改它。如果获得特定三角恒等式的精确结果对您很重要,您可以使用一些检查已知输入的代码来包装本机浮点函数。
The other posts are correct about the practical matter of working with floating point implementations which return results with small errors. However, it would be nice if floating point library implementations would preserve the basic identity of well-known functions:
Math.Sin(Math.PI)
should equal0
,Math.Cos(Math.PI)
should equal-1
,Math.Sin(Math.PI/2)
should equal1
,Math.Cos(Math.PI/2)
should equal0
, etc.You would expect that a floating point library would respect these and other trigonometric identities, whatever the minor errors in its constant values (e.g. Math.PI).
The fact that you're getting a small error from
Math.Cos(Math.PI/2)
indicates that the implementation is calculating the result, rather than pulling it from a table. A better implementation ofMath.Cos
and the other transcendental functions could be more accurate for specific identities.I'm sure in the case of C#, this behavior is expected, and so Microsoft couldn't change it without affecting existing code. If getting the precise result for specific trigonometric identities matters to you, you might wrap the native floating point functions with some code that checks for well-known inputs.
正如 @b1tw153 所注意到的,如果返回 PI/2 倍数的精确值,那就太好了。
这正是 Microsoft 在其
System.Numerics
库中所做的事情;如果您检查 Matrix3x2.CreateRotation 的源代码,您会注意到它们手动处理 n * PI/2 情况:https://github.com/Microsoft/referencesource/blob/master/System.Numerics/System/Numerics/Matrix3x2。 cs#L325As noticed by @b1tw153, it'd be great if exact values were returned for multiples of PI/2.
And that's exactly what Microsoft did in their
System.Numerics
library; if you examine the source code forMatrix3x2.CreateRotation
, you'll note they handle n * PI/2 cases manually: https://github.com/Microsoft/referencesource/blob/master/System.Numerics/System/Numerics/Matrix3x2.cs#L325由于计算结果非常接近 0(零),因此您可以只使用舍入:
因此,根据弧度计算 sin/cos:
如果
yourRadianValue = 90
,返回sin = 1
和cos = 0
。Since the result of the calculation is really close to 0 (zero), you could just use rounding:
So, calculation of sin/cos from radian:
Which if
yourRadianValue = 90
, returnssin = 1
andcos = 0
.