9

我正在将程序从 C# 移植到 java。我已经面对一个事实

爪哇

Math.pow(0.392156862745098,1./3.) = 0.7319587495200227

C#

Math.Pow( 0.392156862745098, 1.0 / 3.0) =0.73195874952002271

最后一位数字会导致进一步计算中的足够差异。有什么方法可以模拟 c# 的 pow 吗?

谢谢

4

6 回答 6

35

只是为了确认 Chris Shain 写的内容,我得到了相同的二进制值:

// Java
public class Test
{
    public static void main(String[] args)
    {
        double input = 0.392156862745098;
        double pow = Math.pow(input, 1.0/3.0);            
        System.out.println(Double.doubleToLongBits(pow));
    }
}

// C#
using System;

public class Test
{
    static void Main()
    {
        double input = 0.392156862745098;
        double pow = Math.Pow(input, 1.0/3.0);            
        Console.WriteLine(BitConverter.DoubleToInt64Bits(pow));
    }
}

两者的输出:4604768117848454313

换句话说,双精度值是完全相同的位模式,您看到的任何差异(假设您会得到相同的结果)都是由于格式而不是值的差异。顺便说一句,该双精度的确切值是

0.73195874952002271118800535987247712910175323486328125

现在值得注意的是,浮点运算中可能会发生明显奇怪的事情,特别是当优化在某些情况下允许 80 位运算但在其他情况下不允许时,等等。

正如 Henk 所说,如果最后一两个方面的差异导致您出现问题,那么您的设计就被破坏了。

于 2012-04-12T20:16:07.103 回答
18

如果您的计算对这种差异很敏感,那么您将需要其他措施(重新设计)。

于 2012-04-12T20:11:57.633 回答
13

最后一位数字导致进一步计算中存在足够的差异

这是不可能的,因为它们是同一个数字。Adouble没有足够的精度来区分0.73195874952002270.73195874952002271; 他们都表示为

0.73195874952002271118800535987247712910175323486328125.

不同之处在于四舍五入:Java 使用 16 位有效数字,而 C# 使用 17 位。但这只是显示问题。

于 2012-04-12T20:23:37.947 回答
8

Java 和 C# 都从 Math.Pow 返回一个 IEEE 浮点数(特别是双精度数)。您看到的差异几乎肯定是由于您将数字显示为十进制时的格式。基础(二进制)值可能是相同的,而您的数学问题在其他地方。

于 2012-04-12T20:13:09.817 回答
1

浮点运算本质上是不精确的。您声称 C# 的答案“更好”,但它们都不是那么准确。例如,Wolfram Alpha(确实更准确)给出了这些值:

http://www.wolframalpha.com/input/?i=Pow%280.392156862745098%2C+1.0+%2F+3.0%29

如果第 17 位的单位差异导致后来的计算出错,那么我认为你的数学有问题,而不是 Java 的pow. 您需要考虑如何重构您的计算,以便它们不依赖于如此小的差异。

于 2012-04-12T20:16:45.373 回答
1

十七位数的精度是任何IEEE 浮点数所能做到的最好的,无论语言如何:

http://en.wikipedia.org/wiki/Double-precision_floating-point_format

于 2012-04-12T22:07:23.517 回答