Reputation: 9206
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
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
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
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
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
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
Reputation: 273244
If your calculations are sensitive to this kind of difference then you will need other measures (a redesign).
Upvotes: 18