Comparing floating point values in Java

Discussion in 'Java' started by Philipp, Dec 30, 2006.

  1. Philipp

    Philipp Guest

    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));
    }
    }
     
    Philipp, Dec 30, 2006
    #1
    1. Advertising

  2. Philipp

    Lew Guest

    Philipp wrote:
    > 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
     
    Lew, Dec 30, 2006
    #2
    1. Advertising

  3. Philipp wrote:
    > 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>
     
    Thomas Schodt, Dec 30, 2006
    #3
  4. Philipp

    Daniel Pitts Guest

    Philipp wrote:
    > 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.
     
    Daniel Pitts, Dec 30, 2006
    #4
  5. Philipp wrote:
    > 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
     
    =?ISO-8859-1?Q?Arne_Vajh=F8j?=, Dec 30, 2006
    #5
  6. Philipp

    Philipp Guest

    Arne Vajhøj wrote:
    > Philipp wrote:
    >> 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
     
    Philipp, Dec 30, 2006
    #6
  7. Philipp wrote:
    > 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
     
    Patricia Shanahan, Dec 30, 2006
    #7
  8. Philipp

    Eric Sosman Guest

    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.)

    --
    Eric Sosman
    lid
     
    Eric Sosman, Dec 30, 2006
    #8
  9. Philipp

    Daniel Pitts Guest

    Eric Sosman wrote:
    > 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.)
    >
    > --
    > Eric Sosman
    > lid


    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.
     
    Daniel Pitts, Dec 31, 2006
    #9
  10. Daniel Pitts wrote:
    > Eric Sosman wrote:
    >> 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.)
    >>
    >> --
    >> Eric Sosman
    >> lid

    >
    > 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
     
    Patricia Shanahan, Dec 31, 2006
    #10
  11. Philipp

    Philipp Guest

    Patricia Shanahan wrote:
    > Philipp wrote:
    >> 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
     
    Philipp, Jan 2, 2007
    #11
  12. Philipp

    Philipp Guest

    Patricia Shanahan wrote:
    > Daniel Pitts wrote:
    >> Eric Sosman wrote:
    >>> 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.)
    >>>
    >>> --
    >>> Eric Sosman
    >>> lid

    >>
    >> 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
     
    Philipp, Jan 2, 2007
    #12
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. nw
    Replies:
    14
    Views:
    545
    Victor Bazarov
    May 2, 2007
  2. Saraswati lakki
    Replies:
    0
    Views:
    1,339
    Saraswati lakki
    Jan 6, 2012
  3. teeshift
    Replies:
    2
    Views:
    257
    Chris Pearl
    Dec 1, 2006
  4. Adam Majewski

    comparing floating point numbers

    Adam Majewski, Jan 29, 2012, in forum: C++
    Replies:
    12
    Views:
    457
    glen herrmannsfeldt
    Feb 13, 2012
  5. Thens

    comparing floating point numbers

    Thens, Jul 10, 2003, in forum: Perl Misc
    Replies:
    3
    Views:
    120
    Michael P. Broida
    Jul 10, 2003
Loading...

Share This Page