Java和C#中的数学“pow”返回略有不同的结果?

Math “pow” in Java and C# return slightly different results?

我是从C到JAVA移植程序。我面临这样一个事实

爪哇

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

C.*

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

最后一个数字在进一步的计算中会产生足够的差异。有没有办法模仿C的战力?

桑克斯


为了确认Chris Shain写了什么,我得到了相同的二进制值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 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));
    }
}

二者产量:46047681178454313

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

1
0.73195874952002271118800535987247712910175323486328125

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

正如亨克所说,如果在最后一位或两位的差异导致了你的问题,那么你的设计就被破坏了。


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


this last digit leads to sufficient differences in further calculations

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

1
0.73195874952002271118800535987247712910175323486328125.

区别在于舍入:Java使用16个有效数字,而C是使用17。但这只是一个显示问题。


Java和C都返回来自Math.Pow的IEEE浮点数(特别是双点数)。您看到的差异几乎可以肯定是由于将数字显示为十进制时的格式设置。底层(二进制)值可能是相同的,而您的数学问题就在其他地方。


不管使用何种语言,17位数字的精度是任何IEEE浮点数都能做到的最好的:

http://en.wikipedia.org/wiki/double-precision_浮点_格式


浮点运算本身就不精确。您声称C答案是"更好的",但两者都不那么准确。例如,Wolfram Alpha(实际上更准确)给出了这些值:

http://www.wolframalpha.com/input/?I=功率%280.392156862745098%2c+1.0+%2f+3.0%29

如果一个单位的第十七位数字的差异导致后来的计算出错,那么我认为你的数学有问题,而不是Java的pow的实现。你需要考虑如何重组你的计算,使它们不依赖于这些细微的差异。