3

I need to increment a float value atomically. I get its int value by calling Float.floatToIntBits on it. If I just do an i++ and convert it back to float, it does not give me the expected value. So how would I go about it?

(I'm trying to create an AtomicFloat through AtomicInteger, hence this question).

EDIT: here's what I did:

Float f = 1.25f;
int i = Float.floatToIntBits(f);
i++;
f = Float.intBitsToFloat(i);

I wanted 2.25, but got 1.2500001 instead.

shrini1000
  • 7,038
  • 12
  • 59
  • 99

2 Answers2

5

The reason is that the bits you get from floatToIntBits represents

  1. sign
  2. exponent
  3. mantissa

laid out like this:

Repr:  Sign   Exponent          Mantissa
Bit:    31   30......23  22.....................0

Incrementing the integer storing these fields with 1 won't increment the float value it represents by 1.

I'm trying to create an AtomicFloat through AtomicInteger, hence this question

I did precisely this in an answer to this question:

To add functionality to increment the float by one, you could copy the code of incrementAndGet from AtomicInteger (and change from int to float):

public final float incrementAndGet() {
    for (;;) {
        float current = get();
        float next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

(Note that if you want to increment the float by the smallest possible value, you take the above code and change current + 1 to current +Math.ulp(current).)

Community
  • 1
  • 1
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • thanks for the answer. But the code you've shown for incrementAndGet won't use CAS operation, right (the way AtomicInteger does)? So it would have to be synchronized in the usual way? – shrini1000 Mar 29 '12 at 12:53
  • The `incramentAndGet` method I posted in my answer was intended to be included in the `AtomicFloat` class that I described in my [other answer](http://stackoverflow.com/questions/5505460/java-is-there-no-atomicfloat-or-atomicdouble/5505512#5505512). – aioobe Mar 29 '12 at 13:19
  • btw, I took a look at AtomicInteger and how it uses 'unsafe' for CAS. 'unsafe' does not have any api to compareAndSwap float/double. Is that the reason why we don't have direct support for AtomicFloat/AtomicDouble? – shrini1000 Mar 30 '12 at 06:04
  • Don't think so. I posted the "official" reason in tha answer I linked to. – aioobe Mar 30 '12 at 06:07
2

The atomic part can be implemented atop compareAndSet for a wrapper class as shown in the link of aioobe. The increment operators of AtomicInteger are implemented like that.

The increment part is a completely different problem. Depending on what you mean by "increment a float", it either requires you to add one to the number, or increment it by one ULP. For the latter, in Java 6, the Math.nextUp method is what you are looking for. For decrement by one ULP, the Math.nextAfter method is useful.

Christian Semrau
  • 8,913
  • 2
  • 32
  • 39
  • 1
    Note that nextAfter requires an extra "dummy" argument such as `Float.MAX_VALUE`, whereas `Math.ulp` directly gives the distance to the next float. – aioobe Mar 29 '12 at 08:47
  • As I just saw, `Math.nextUp(f)` (Java 6) returns the value of `f+ulp(f)` without requiring the extra argument that `nextAfter(f, INFINITY)` needs, and probably is faster than computing `f+ulp(f)` as is. – Christian Semrau Mar 29 '12 at 19:45