Math.Cos & Math.Sin in C#

本文关键字:Math in Sin amp Cos | 更新日期: 2023-09-27 17:57:20

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

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

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

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

Math.Cos(radians)

我最终得到的答案是:6.12303176911189E-17

这到底是怎么回事? 90度的余弦应该是0,那为什么我会得到这样的偏差......更重要的是,我该如何阻止它?

Math.Cos & Math.Sin in C#

让我用另一个问题回答你的问题:你认为 6.12303176911189E-17 离 0 有多远?你所说的偏差实际上是由于浮点数的内部存储方式。我建议您阅读以下文章。在 .NET 中,它们使用 IEEE 754 标准进行存储。

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

你应该使用舍入

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

结果将是:罪: 1系数: 0

阅读浮点运算。它永远不会,也永远不可能是准确的。永远不要完全比较任何东西,但要检查数字是否相差一个(小)epsilon。

其他帖子关于使用浮点实现的实际问题是正确的,浮点实现返回的结果带有小错误。但是,如果浮点库实现能够保留已知函数的基本标识,那就太好了:

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

你会期望浮点库会尊重这些和其他三角恒等式,无论其常量值(例如 Math.PI)中存在哪些小错误。

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

我敢肯定,在 C# 的情况下,这种行为是意料之中的,因此Microsoft无法在不影响现有代码的情况下更改它。如果获得特定三角恒等式的精确结果对您很重要,则可以使用一些检查已知输入的代码包装本机浮点函数。

由于计算结果非常接近 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

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