Comparing floating point values in Java

P

Philipp

Hello,
I'm aware of problems (rounding, NaN etc) when comparing floating point
values in computers.
In C++ this goes a bit further as you cannot compare with certitude
floating point numbers even if you have made exactly the same operations
on each of them (see eg:
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18 )

My question: In Java, will unchanged values compare strictly true if equal?
Is it _guaranteed_ that the following code does output "true" on all JVMs?

Thanks for answers. Phil

example code:
public class Test {
public static void main(String[] args) {
float a = 1;
float b = 1;
System.out.println("a == b?: " + (a == b));
}
}
 
L

Lew

Philipp said:
float a = 1;
float b = 1;

Side note: consider explicitly setting float variables to float constants
rather than integer constants:

float a = 1.f;

This prevents conversion from being an issue.

Generally you can count on constants comparing equal if they represent the
same value. Generally you cannot count on calculated values equaling
differently-calculated values even were they mathematically equivalent given
infinite precision.

It makes a difference what values you wish to represent. Not all values are
precisely representable in limited-precision floating point.

Read
<http://docs.sun.com/source/806-3568/ncg_goldberg.html>
available as a PDF from
<http://www.physics.ohio-state.edu/~dws/grouplinks/floating_point_math.pdf>
among other places.

- Lew
 
T

Thomas Schodt

Philipp said:
I'm aware of problems (rounding, NaN etc) when comparing floating point
values in computers.
In Java, will unchanged values compare strictly true if equal?
Is it _guaranteed_ that the following code does output "true" on all JVMs?

Thanks for answers. Phil

example code:
public class Test {
public static void main(String[] args) {
float a = 1;
float b = 1;
System.out.println("a == b?: " + (a == b));
}
}

I would suggest that
any JVM where it would output false
is probably non-compliant.

Your example may be somewhat lacking
as many scalar values
and many fractions where the denominator is a cardinal exponent of 2
correspond exactly
to a floating point representation.

Personally I like to think of floating point values
as representing bounded infinite sets of real values
(or not bounded - for positive and negative infinity).


There are some that take a dim view on the liberties Sun / Gosling took
in the way Java deals with IEEE754 values, eg.;
<http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf>
 
D

Daniel Pitts

Philipp said:
Hello,
I'm aware of problems (rounding, NaN etc) when comparing floating point
values in computers.
In C++ this goes a bit further as you cannot compare with certitude
floating point numbers even if you have made exactly the same operations
on each of them (see eg:
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18 )

My question: In Java, will unchanged values compare strictly true if equal?
Is it _guaranteed_ that the following code does output "true" on all JVMs?

Thanks for answers. Phil

example code:
public class Test {
public static void main(String[] args) {
float a = 1;
float b = 1;
System.out.println("a == b?: " + (a == b));
}
}

Look into StrictMath.

It might also be worthwhile to learn how to calculate error, and
compare signifigant figures only. If you only need a "probably equal",
then you can use a delta, eg:

public class FloatEquality {
public static boolean areEqual(float a, float b, float delta) {
return Math.abs(a - b) < delta;
}
public static float DELTA_F = 0.00000001f;
public static void main(String[] args) {
float a = 1f;
float b = 1f;
System.out.println("a == b?: " + areEqual(a, b, DELTA_F);
}
}

Hope this helps.

Daniel.
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Philipp said:
I'm aware of problems (rounding, NaN etc) when comparing floating point
values in computers.
In C++ this goes a bit further as you cannot compare with certitude
floating point numbers even if you have made exactly the same operations
on each of them (see eg:
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18 )

My question: In Java, will unchanged values compare strictly true if equal?
Is it _guaranteed_ that the following code does output "true" on all JVMs?
example code:
public class Test {
public static void main(String[] args) {
float a = 1;
float b = 1;
System.out.println("a == b?: " + (a == b));
}
}

Most C++ implementations use IEEE floating point.

Java uses IEEE floating point.

You should expect the same floating point issues in
Java as in C++.

Your example is not equivalent to the example in your link.

I believe that the above should always write true in Java.

But in general you should not use == to compare floating
points in Java either.

Your example are just more simple than real life code.

Arne
 
P

Philipp

Arne said:
Philipp said:
I'm aware of problems (rounding, NaN etc) when comparing floating
point values in computers.
In C++ this goes a bit further as you cannot compare with certitude
floating point numbers even if you have made exactly the same
operations on each of them (see eg:
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18 )

My question: In Java, will unchanged values compare strictly true if
equal?
Is it _guaranteed_ that the following code does output "true" on all
JVMs?
example code:
public class Test {
public static void main(String[] args) {
float a = 1;
float b = 1;
System.out.println("a == b?: " + (a == b));
}
}

Your example is not equivalent to the example in your link.

Yes I'm aware of that. The point in the link is that compiler
optimization can lead to unequal floats even if exactly the same
operations were performed on it. Is this also true for Java?
But in general you should not use == to compare floating
points in Java either.
Agree

Your example are just more simple than real life code.

No! (If I ask the question it's because I met this problem)

I was calculating an array of float values from some user input. But
sometimes (rarely) the calculation cannot be done (this is correct
behavior).
I then want to mark these values by setting them to -1 and treat this
special case later on. So I later need to test for -1 in my array.

Philipp
 
P

Patricia Shanahan

Philipp said:
Hello,
I'm aware of problems (rounding, NaN etc) when comparing floating point
values in computers.
In C++ this goes a bit further as you cannot compare with certitude
floating point numbers even if you have made exactly the same operations
on each of them (see eg:
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18 )

My question: In Java, will unchanged values compare strictly true if equal?
Is it _guaranteed_ that the following code does output "true" on all JVMs?

Thanks for answers. Phil

example code:
public class Test {
public static void main(String[] args) {
float a = 1;
float b = 1;
System.out.println("a == b?: " + (a == b));
}
}

Java does not permit reordering optimizations that could affect a
floating point result.

In strictfp mode, the exact, bit-by-bit, result is predictable from the
source code for any Java implementation.

Without strictfp, the implementation is allowed, but never required, to
use a wider exponent for some intermediate results. That may suppress an
overflow to infinity or underflow to zero (for numbers too tiny to be
represented as denormalized with the correct exponent width).

That would allow some calculations to get different results depending on
issues such as whether a value was kept in a register or stored to a
memory temporary.

If you are just concerned about issues such as whether Java will
arbitrarily reorder expressions, you are fine in default mode. If you
really need exact equality on every identical source calculation, you
need strictfp.

Patricia
 
E

Eric Sosman

Philipp said:
[...]

I was calculating an array of float values from some user input. But
sometimes (rarely) the calculation cannot be done (this is correct
behavior).
I then want to mark these values by setting them to -1 and treat this
special case later on. So I later need to test for -1 in my array.

Perhaps you can avoid the entire issue by choosing a
different "distinguished value." Float.NaN, maybe, using
the Float.isNaN(float) method instead of an == test. (NaN
seems a more natural surrogate for "does not compute," too.)
 
D

Daniel Pitts

Eric said:
Philipp said:
[...]

I was calculating an array of float values from some user input. But
sometimes (rarely) the calculation cannot be done (this is correct
behavior).
I then want to mark these values by setting them to -1 and treat this
special case later on. So I later need to test for -1 in my array.

Perhaps you can avoid the entire issue by choosing a
different "distinguished value." Float.NaN, maybe, using
the Float.isNaN(float) method instead of an == test. (NaN
seems a more natural surrogate for "does not compute," too.)

Or even have a seperate boolean array to specify valid results.
Having a magic value isn't generally a good idea, although NaN would be
the way to go if you did.
 
P

Patricia Shanahan

Daniel said:
Eric said:
Philipp said:
[...]

I was calculating an array of float values from some user input. But
sometimes (rarely) the calculation cannot be done (this is correct
behavior).
I then want to mark these values by setting them to -1 and treat this
special case later on. So I later need to test for -1 in my array.
Perhaps you can avoid the entire issue by choosing a
different "distinguished value." Float.NaN, maybe, using
the Float.isNaN(float) method instead of an == test. (NaN
seems a more natural surrogate for "does not compute," too.)

Or even have a seperate boolean array to specify valid results.
Having a magic value isn't generally a good idea, although NaN would be
the way to go if you did.

Since the special cases are rare, one could also describe them by having
e.g. a HashSet<Integer> containing the index values of the special cases.

Using any magic value, including NaN, has the risk that a bug elsewhere
in the code will get hidden as the special case. The risk can be reduced
by using a specific NaN value and Float.floatToRawIntBits to check for it.

Patricia
 
P

Philipp

Patricia said:
Philipp said:
Hello,
I'm aware of problems (rounding, NaN etc) when comparing floating
point values in computers.
In C++ this goes a bit further as you cannot compare with certitude
floating point numbers even if you have made exactly the same
operations on each of them (see eg:
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18 )

My question: In Java, will unchanged values compare strictly true if
equal?
Is it _guaranteed_ that the following code does output "true" on all
JVMs?

Thanks for answers. Phil

example code:
public class Test {
public static void main(String[] args) {
float a = 1;
float b = 1;
System.out.println("a == b?: " + (a == b));
}
}

Java does not permit reordering optimizations that could affect a
floating point result.

In strictfp mode, the exact, bit-by-bit, result is predictable from the
source code for any Java implementation.

Without strictfp, the implementation is allowed, but never required, to
use a wider exponent for some intermediate results. That may suppress an
overflow to infinity or underflow to zero (for numbers too tiny to be
represented as denormalized with the correct exponent width).

That would allow some calculations to get different results depending on
issues such as whether a value was kept in a register or stored to a
memory temporary.

If you are just concerned about issues such as whether Java will
arbitrarily reorder expressions, you are fine in default mode. If you
really need exact equality on every identical source calculation, you
need strictfp.

Thanks for that very precise and complete response.
Phil
 
P

Philipp

Patricia said:
Daniel said:
Eric said:
Philipp wrote:
[...]

I was calculating an array of float values from some user input. But
sometimes (rarely) the calculation cannot be done (this is correct
behavior).
I then want to mark these values by setting them to -1 and treat this
special case later on. So I later need to test for -1 in my array.
Perhaps you can avoid the entire issue by choosing a
different "distinguished value." Float.NaN, maybe, using
the Float.isNaN(float) method instead of an == test. (NaN
seems a more natural surrogate for "does not compute," too.)

Or even have a seperate boolean array to specify valid results.
Having a magic value isn't generally a good idea, although NaN would be
the way to go if you did.

Since the special cases are rare, one could also describe them by having
e.g. a HashSet<Integer> containing the index values of the special cases.

Using any magic value, including NaN, has the risk that a bug elsewhere
in the code will get hidden as the special case. The risk can be reduced
by using a specific NaN value and Float.floatToRawIntBits to check for it.

Thanks for pointing out the NaN possibility which I did not think of
before and is really more "beautiful".

The two other possibilities (using a separate array to mark the bad
values and using a hashset with indexes of bad values) seemed a bit
overkill at first. But maybe this is really the cleaner way to go.

Happy New Year
Phil
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top