2011-05-21 200 views
8

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

具有90度的示例输入I的值转换为弧度用下面的代码:

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

这使我1.5707963267949弧度 然后,当我使用

Math.Cos(radians) 

我结束了答案是:6.12303176911189E-17

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

+0

绝对舍入为0.当您将该值转换为字符串时,请使用格式说明符,以便用户按照预期的方式看到它。 – 2011-05-21 15:19:31

+0

好吧,我认为精度的缺乏是由于浮点类型的精度不足造成的,但Windows Calculator如何设法让答案死灰复燃,它只是欺骗并使用查找表? – elaverick 2011-05-21 15:45:02

+1

@elaverick - 谁说Windows计算器正在使用.Net双打(不是)或任何浮点类型(它不是)。谁说它会输出精确的计算结果而不是运用理智的舍入规则? – 2011-05-21 15:48:58

回答

13

让我用另一个回答你的问题:你认为6.12303176911189E-17从0开始有多远?你所说的deviance实际上是由于内部存储浮点数的方式。我会建议你阅读following article。在.NET中,它们使用IEEE 754 standard进行存储。

+2

应用一些基本的三角函数,两个颗粒之间的距离为1E-17 * 9.4E15〜= 0.57 = 57cm,其中一个光年移动一个光年。我认为这两者都不值得担心。 – 2015-12-11 12:29:06

2

请阅读floating point arithmetic。它永远不会是确切的。切勿与任何东西完全比较,但检查数字是否相差(小)epsilon。

+3

它有时是确切的。只是不是所有的时间。 – 2011-05-21 15:21:01

+0

这与计算机中没有使用随机性的其他内容完全相同。问题在于大多数人(包括计算机程序员)使用十进制表示的普遍注意。 – 2011-05-21 15:36:23

+2

@Damien_The_Unbeliever完全彻底的错误。这是不准确的,因为这组实数不能通过任何物理手段准确表示;它与数字基础无关。例如,计算机中的其他东西可以完全表示为......整数和有理数。即使这里的问题可以完全通过符号而不是数字表示来表达,但这只能带你到目前为止。 – 2014-06-05 00:49:23

5

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

1

由于计算的结果是非常接近0(零),你可以只使用四舍五入:

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

所以,计算罪/从弧度 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)等于0
Math.Cos(Math.PI)等于-1
Math.Sin(Math.PI/2)等于1
Math.Cos(Math.PI/2)应该等于0

你会期望浮点库会尊重这些和其他trigonometric identities,无论常量值中的小错误是多少(例如, Math.PI)。

Math.Cos(Math.PI/2)得到一个小错误的事实表明该实现正在计算结果,而不是从表中拉出来。更好地实现Math.Cos和其他超越函数可能更准确的具体身份。

我敢肯定,在C#的情况下,这种行为是预期的,所以微软无法改变它,而不会影响现有的代码。如果为特定的三角身份获取精确的结果对您来说很重要,那么您可以使用一些检查已知输入的代码来包装本地浮点函数。