C#中的Math.Cos和Math.Sin

问题描述 投票:8回答:7

我正在尝试一些我认为应该相当简单的事情。我有一个角度,一个位置和一个距离,我想从这些信息中找到X,Y坐标。

使用90度的示例输入,我使用以下代码将值转换为弧度:

public double DegreeToRadian(float angle)
{
  return Math.PI * angle / 180.0;
}

这给了我1.5707963267949弧度然后当我使用

Math.Cos(radians)

我最终得到了一个答案:6.12303176911189E-17

到底他妈发生了什么? 90度的余弦应该是0,所以为什么我会得到这样的偏差...更重要的是我怎么能阻止它呢?

c# trigonometry cosine sine
7个回答
6
投票

见上面的答案。请记住,6.12303176911189E-17是0.00000000000000006(我甚至可能错过了零!)所以这是一个非常非常小的偏差。


2
投票

阅读floating point arithmetic。它永远也永远不会是精确的。永远不要与任何东西完全比较,但要检查数字是否因(小)epsilon而不同。


1
投票

由于计算结果非常接近0(零),您可以使用舍入:

Math.Round(result, 4): // 4 decimals, e.g.: 2.1234

所以,从弧度计算sin / cos:

const double Deg = Math.PI / 180;
double sin = Math.Round(Math.Sin(yourRadianValue * Deg), 4);
double cos = Math.Round(Math.Cos(yourRadianValue * Deg), 4); // 0.0000...06 becomes 0

如果yourRadianValue = 90,返回sin = 1cos = 0


1
投票

其他帖子对于使用浮点实现的实际问题是正确的,这些实现返回小错误的结果。但是,如果浮点库实现保留了众所周知的函数的基本身份,那将是很好的:

Math.Sin(Math.PI)应该等于0Math.Cos(Math.PI)应该等于-1Math.Sin(Math.PI/2)应该等于1Math.Cos(Math.PI/2)应该等于0等。

您可以预期浮点库会尊重这些和其他trigonometric identities,无论其常量值中的小错误(例如Math.PI)。

您从Math.Cos(Math.PI/2)获得一个小错误的事实表明该实现正在计算结果,而不是从表中提取它。更好地实现Math.Cos和其他超越函数对于特定身份可能更准确。

我确信在C#的情况下,这种行为是预期的,因此Microsoft无法在不影响现有代码的情况下对其进行更改。如果获得特定三角标识的精确结果对您很重要,则可以使用一些检查已知输入的代码来包装本机浮点函数。


1
投票

你应该使用四舍五入

var radians = Math.PI * degres / 180.0;
var cos = Math.Round(Math.Cos(radians), 2);
var sin = Math.Round(Math.Sin(radians), 2);

结果将是:sin:1 cos:0


0
投票

正如@ b1tw153所注意到的那样,如果为PI / 2的倍数返回了精确值,那就太好了。而这正是微软在他们的System.Numerics库中所做的事情;如果你检查Matrix3x2.CreateRotation的源代码,你会注意到它们手动处理n * PI / 2个案例:https://github.com/Microsoft/referencesource/blob/master/System.Numerics/System/Numerics/Matrix3x2.cs#L325

© www.soinside.com 2019 - 2024. All rights reserved.