Java和C#中的双精度浮点数精度差异

3

这并没有回答问题。

我在Java和C#中运行了完全相同的代码,但结果却不同。

为什么会这样呢?因为在两种语言中,double具有完全相同的规格

double是Java中表示64位IEEE 754浮点数的类型。

double是C#中以IEEE 754格式表示64位双精度浮点数的类型。


Java

double a = Math.pow(Math.sin(3), 2);
double b = Math.pow(Math.cos(3), 2);
System.out.println(a);   // 0.01991485667481699
System.out.println(b);   // 0.9800851433251829
System.out.println(a+b); // 0.9999999999999999

C#

double a = Math.Pow(Math.Sin(3), 2);
double b = Math.Pow(Math.Cos(3), 2);
Console.WriteLine(a);   // 0.019914856674817
Console.WriteLine(b);   // 0.980085143325183
Console.WriteLine(a+b); // 1

3
我怀疑这更多与控制台输出对数字进行四舍五入有关,而不是与基础数学有关。 - Paolo
3
你确定 SinCos 的实现是一样的吗? - RealSkeptic
@RealSkeptic 我一点也不确定。Paolo 是的,老师也告诉我这样,但我想要一个适当的解释。 - Yassin Hajaj
@RealSkeptic 看起来这是Java中的本地方法。我认为在C#中也是一样的,因此我找不到确切的实现方式。 - Yassin Hajaj
3个回答

7

0

问题的根源在于浮点数是不精确的,计算甚至不能被依赖于确定性。但它们是接近的。

很可能差异可能是因为CLR允许内部使用双精度作为80位数字进行运算。您永远不会看到超过64位,但处理器将使用80位。我不确定Java如何处理浮点数。它可能是相同的。

关于这个主题有很多内容,但这里有一些来自Google的轻松阅读,可能会引起您的兴趣。


0

IEEE754 在所需操作和可选操作之间做了区分:

  • 所需操作,例如加法、减法等必须精确舍入
  • 可选操作无需精确舍入。这些操作的列表包括所有三角函数(和其他函数),它们由实现进行处理。

因此,标准没有保证不同实现中的 sincos 实现应该匹配。

更多信息在此处在此处


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接