Stepan Yakovenko
Stepan Yakovenko

Reputation: 9206

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

I am porting program from C# to java. I've faced a fact that

Java

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

C#

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

this last digit leads to sufficient differences in further calculations. Is there any way to emulate c#'s pow?

Thanx

Upvotes: 9

Views: 2167

Answers (6)

duffymo
duffymo

Reputation: 308763

Seventeen digits' precision is the best any IEEE floating point number can do, regardless of language:

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

Upvotes: 1

dan04
dan04

Reputation: 90995

this last digit leads to sufficient differences in further calculations

That's impossible, because they're the same number. A double doesn't have enough precision to distinguish between 0.7319587495200227 and 0.73195874952002271; they're both represented as

0.73195874952002271118800535987247712910175323486328125.

The difference is the rounding: Java is using 16 significant digits and C# is using 17. But that's just a display issue.

Upvotes: 13

Ethan Brown
Ethan Brown

Reputation: 27282

Floating-point arithmetic is inherently imprecise. You are claiming that the C# answer is "better" but neither of them are that accurate. For example, Wolfram Alpha (which is much more accurate indeed) gives these values:

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

If a unit's difference in the 17th digit is causing later computations to go awry, then I think there's a problem with your math, not with Java's implementation of pow. You need to think about how to restructure your computations so that they don't rely on such minor differences.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500505

Just to confirm what Chris Shain wrote, I get the same binary values:

// 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));
    }
}

Output of both: 4604768117848454313

In other words, the double values are exactly the same bit pattern, and any differences you're seeing (assuming you'd get the same results) are due to formatting rather than a difference in value. By the way, the exact value of that double is

0.73195874952002271118800535987247712910175323486328125

Now it's worth noting that distinctly weird things can happen in floating point arithmetic, particularly when optimizations allow 80-bit arithmetic in some situations but not others, etc.

As Henk says, if a difference in the last bit or two causes you problems, then your design is broken.

Upvotes: 35

Chris Shain
Chris Shain

Reputation: 51329

Both Java and C# return a IEEE floating point number (specifically, a double) from Math.Pow. The difference that you are seeing is almost certainly due to the formatting when you display the number as decimal. The underlying (binary) value is probably the same, and your math troubles lie elsewhere.

Upvotes: 8

Henk Holterman
Henk Holterman

Reputation: 273244

If your calculations are sensitive to this kind of difference then you will need other measures (a redesign).

Upvotes: 18

Related Questions