# Java implementation of Comparing floating point numbers

posted 8 years ago

This is more of an advanced numerical analysis question than about advanced Java....

In Comparison of Floating Point numbers

Bruce Dawson talks about how comparing floats and doubles is a lot harder than it looks.

He describes the problems, and provides some C-language code that does the comparison quickly and correctly.

java.lang.math.IEEEremainder() does something relative to this, but I can't follow exactly what from either the javadocs or chasing references to the real IEEE standad

In Comparison of Floating Point numbers

Bruce Dawson talks about how comparing floats and doubles is a lot harder than it looks.

He describes the problems, and provides some C-language code that does the comparison quickly and correctly.

java.lang.math.IEEEremainder() does something relative to this, but I can't follow exactly what from either the javadocs or chasing references to the real IEEE standad

Bill Shirley

Ranch Hand

Posts: 457

posted 8 years ago

Is there a question?

Yes, floating point representation in binary format is a very tricky computer science problem. Comparing floating point numbers is particularly tricky.

Since Java post-dates IEEE 754, I assume is uses that standards comparison methods, but I don't rely on floats or doubles enough to ever bother.

Yes, floating point representation in binary format is a very tricky computer science problem. Comparing floating point numbers is particularly tricky.

Since Java post-dates IEEE 754, I assume is uses that standards comparison methods, but I don't rely on floats or doubles enough to ever bother.

Bill Shirley - bshirley - frazerbilt.com

if (Posts < 30) you.read( JavaRanchFAQ);

posted 8 years ago

Well, there's java.lang.Float.intBitToFloat() and floatToIntBits() and friends; there are analagous methods in the Double class too. These should help satisfy your curiosity, if nothing else.

Originally posted by Pat Farrell:

The tricks he uses are only applicable for C, they rely upon pointers and using the same location in memory as both a float and an int. Not possible in Java

Well, there's java.lang.Float.intBitToFloat() and floatToIntBits() and friends; there are analagous methods in the Double class too. These should help satisfy your curiosity, if nothing else.

posted 8 years ago

Thanks. I'm more than curious, I'm looking for a good implementation. For suitable values of good.

Originally posted by Ernest Friedman-Hill:

Well, there's java.lang.Float.intBitToFloat() and floatToIntBits() and friends; there are analagous methods in the Double class too. These should help satisfy your curiosity, if nothing else.

Thanks. I'm more than curious, I'm looking for a good implementation. For suitable values of good.

Nicholas Jordan

Ranch Hand

Posts: 1282

posted 8 years ago

Source: Floating point remainder in Kaffe

According to the JLS (S15.16.3) Java's floating point remainder (using the '%' operator) is *different from* the java.lang.Math.IEEEremainder()

function. The operator is based on truncating division while the

function is based on rounding division. You might think that this

won't add up to much, but 8.0 % 3.0 results in -1.0 with rounding

division versus 2.0 with truncating division.

Source: Floating point remainder in Kaffe

posted 8 years ago

Hi Pat,

OK, I went and looked at the (interesting) linked document. I think you could work from that pretty well, with the following translation: when they have

*(int*)&A

the Java equivalent would be

Float.floatToIntBits(A)

so his final comparison function would be

I did some minimal testing and this seems to work as advertised, but you should probably do more extensive testing.

OK, I went and looked at the (interesting) linked document. I think you could work from that pretty well, with the following translation: when they have

*(int*)&A

the Java equivalent would be

Float.floatToIntBits(A)

so his final comparison function would be

I did some minimal testing and this seems to work as advertised, but you should probably do more extensive testing.

posted 8 years ago

Originally posted by Ernest Friedman-Hill:

I have done a bit of testing and I don't grok this line. The key, which I couldn't tell until I fired up some test cases and the debugger, is that this comparison is done on the difference of the "integer" values. I have no idea what scale is applicable, ideal, good.

consider these values: ( 0.1F, 0.10000001F)

on my system (intel x86 32 bits) I get a raw difference of 536870912

aka 536,870,912 or 500 million. This fails your assertion test.

I can see that the integer comparison style is a lot faster, but it looks a lot less understandable than the division based relative calculation that the paper says is not good (it has lots of floating abs() etc.

posted 8 years ago

I've put up some source files, and JUnit tests on my server for others who are interested.

Math java source, Complex, AboutEquals

Math java source, Complex, AboutEquals

posted 8 years ago

Hmmm. I don't know how that could be. The answer should be the same on every system, guaranteed by IEEE floating-point standard. On my system this difference is actually 1, which is as it should be.

"ulp" stands for "unit of least precision". A difference of one ulp between two floats indicates that they're "adjacent" floats; that there's no value in between them. If I were using this method I'd probably pass values between 1 and 5 most of the time.

There are ulp(float) and ulp(double) methods in java.lang.Math which show you the absolute magnitude of the difference between a float or double and its nearest neighbor; you should check these out. Based on what I saw here you should find that ulp(0.1) is roughly 0.00000001.

Originally posted by Pat Farrell:

consider these values: ( 0.1F, 0.10000001F)

on my system (intel x86 32 bits) I get a raw difference of 536870912

aka 536,870,912 or 500 million. This fails your assertion test.

Hmmm. I don't know how that could be. The answer should be the same on every system, guaranteed by IEEE floating-point standard. On my system this difference is actually 1, which is as it should be.

"ulp" stands for "unit of least precision". A difference of one ulp between two floats indicates that they're "adjacent" floats; that there's no value in between them. If I were using this method I'd probably pass values between 1 and 5 most of the time.

There are ulp(float) and ulp(double) methods in java.lang.Math which show you the absolute magnitude of the difference between a float or double and its nearest neighbor; you should check these out. Based on what I saw here you should find that ulp(0.1) is roughly 0.00000001.

posted 8 years ago

Which is one of the reasons I put the code up with URL above

Originally posted by Ernest Friedman-Hill:

Hmmm. I don't know how that could be. The answer should be the same on every system, guaranteed by IEEE floating-point standard. On my system this difference is actually 1, which is as it should be.

Which is one of the reasons I put the code up with URL above

posted 6 years ago

Reviving an ancient thread since I'm doing more testing in it:

Checking the Math.ulp() functions shows that Dr Friedman-Hill is right.

For floating: f: a: 0.100000, ulpA: 7.45058e-09,

for double: d: a: 0.100000, ulpA: 1.38778e-17,

and for more obscure values, testing one that is 10 ^ -41, which is very close to zero:

d: a: 1.00000e-41, ulpA: 1.27447e-57,

40 more orders of magnitude smaller:

d: a: 1.00000e-81, ulpA: 1.17042e-97,

Ernest Friedman-Hill wrote:There are ulp(float) and ulp(double) methods in java.lang.Math which show you the absolute magnitude of the difference between a float or double and its nearest neighbor; you should check these out. Based on what I saw here you should find that ulp(0.1) is roughly 0.000 000 01.

Checking the Math.ulp() functions shows that Dr Friedman-Hill is right.

For floating: f: a: 0.100000, ulpA: 7.45058e-09,

for double: d: a: 0.100000, ulpA: 1.38778e-17,

and for more obscure values, testing one that is 10 ^ -41, which is very close to zero:

d: a: 1.00000e-41, ulpA: 1.27447e-57,

40 more orders of magnitude smaller:

d: a: 1.00000e-81, ulpA: 1.17042e-97,