Win a copy of Re-engineering Legacy Software this week in the Refactoring forum
or Docker in Action in the Cloud/Virtualization forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Java implementation of Comparing floating point numbers

 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
Bill Shirley
Ranch Hand
Posts: 457
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Anybody got an implementation? or URL?
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
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24208
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24208
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks, I'll hack arround with your version.

I agree, tt is a fairly interesting question/ problem space
 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I've put up some source files, and JUnit tests on my server for others who are interested.
Math java source, Complex, AboutEquals
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24208
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Reviving an ancient thread since I'm doing more testing in it:


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,
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic