0

Both int and float in Java are 32 bits size values. Is it possible to program a pair of functions

int toInt(float f);
float toFloat(int n);

such that if f1 and f2 are arbitrary float non-NaN values and i1 and i2 are arbitraty int values:

  • f1 < f2 if and only if toInt(f1) < toInt(f2)
  • f1 > f2 if and only if toInt(f1) > toInt(f2)
  • f1 == f2 if and only if toInt(f1) == toInt(f2)
  • toInt(toFloat(i1) == i1
  • toFloat(toInt(f1)) == f1

Edit: I have edited the question to exclude NaN values for float, thanks to the answers clarifying what happens with those.

Rüdiger Klaehn
  • 12,445
  • 3
  • 41
  • 57
José D.
  • 4,175
  • 7
  • 28
  • 47

6 Answers6

7

Yes. IEEE floats and doubles are arranged in such a way that you can compare them by doing an unsigned comparison of the raw binary representation. The function to convert from float to raw integer and back are java.lang.Float.floatToIntBits and java.lang.Float.intBitsToFloat. These functions are processor intrinsics, so they have an extremely low cost.

The same is true for longs and doubles. Here the conversion functions are java.lang.Double.doubleToLongBits and java.lang.Double.longBitsToDouble.

Note that if you want to use the normal signed comparison for your integers, you have to do some additional transformation in addition to the conversion to integer.

The only exception to this rule is NaN, which does not permit a total ordering anyway.

Rüdiger Klaehn
  • 12,445
  • 3
  • 41
  • 57
  • A signed comparison on `x ^ Integer.MIN_VALUE` with `y ^ Integer.MIN_VALUE` is equivalent to an unsigned comparison of `x` and `y`. – Louis Wasserman Jul 26 '14 at 21:34
1

I see what you're saying. At first I had a different interpretation of your question. As everyone else has mention: yes. Use the articles described here and here to explain why we should use the methods described by @Peter Lawrey in order to compare the underlying bit pattern between ints and floats

Community
  • 1
  • 1
Devarsh Desai
  • 5,984
  • 3
  • 19
  • 21
1

You can use

int n = Float.floatToRawIntBits(f);

float f2 = Float.intBitToFloat(n);

int n2 = Float.floatToRawIntBits(f2);

assert n == n2; // always
assert f == f2 || Float.isNaN(f);

The raw bits as a int have the same sort order as the original float with the exception of the NaN values which are not comparable as a float value have a value as an int

Note: there is multiple values for NaN which are not equal to each other as float

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

No you cannot

There are 2^32 possible int values, all of which are distinct. However, thee are less than 2^32 floats; ie. 7FF0000000000001 to 7FF7FFFFFFFFFFFF represent NaN's,

There fore, you have more ints than floats an cannot distinctly map them to each other as toFloat(i1) would not be cable of producing a distinct float for every int

vandale
  • 3,600
  • 3
  • 22
  • 39
  • Technically there is multiple NaN values so the `int` in this range is preserved even if there is no way to tell as `float` values. – Peter Lawrey Jul 26 '14 at 21:09
1

The answer from Rüdiger Klaehn gives the normal case, but it lacks some details. The bijection exits only in the domain of nice and clean floats.

Notice : representation of an IEEE float is sign_bit(1 bit) exponent(8 bits) sinificand(23 bits) and the value is : (-1)<sup>sign</sup> * 2<sup>exp</sup> * significand in clean cases. In fact, the 23 bits represent the fractional part of the actual significand, the integer part being 1.

All is fine for 0 < exp < 255 (which correspond to normal not null floats ) as an unsigned byte and in that domain you have a bijection.

For exp == 255 you have the infinite values is significand == 0 and all the NaN for significand != 0 - ok, you explicitely excluded them.

But for exp == 0 there are still weird things : when significand == 0 you have +0 and -0. I am not sure if they are considered equal. If anybody knows, please feel free to edit the post. But as integer values, they will of course be different.

And when exp == 0 and significand != 0 you find denormalized numbers ... which while not being equal will be converted to either 0 of the littlest number not being 0.

So if you want a bijection only use normal numbers having 0 < exp < 255< and avoid NaN, infinite, 0 and denormal numbers where things are weird.

References :

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
0
f1 == f2

is impossible, see this answer for more info. You will need to include a delta if you actually want to APPROXIMATE your equality-check.

Community
  • 1
  • 1
specializt
  • 1,913
  • 15
  • 26