Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Raising a float to a certain power in Java

I have a variable x of type float which should be raised to a certain power p. If x was a double I could have used Math.pow(x, p). Is it possible to calculate x^p so that the result will also be a float?

like image 413
snakile Avatar asked Feb 13 '23 19:02

snakile


2 Answers

Evaluating pow in double and converting to float will almost always produce the same results as evaluating a float implementation of pow. To see this, consider the exact mathematical value of xp. If, using round-to-nearest mode, it is correctly rounded to a double and then correctly rounded to a float, the result is the same as rounding directly to a float unless the rounding to a double moved the value across a boundary where rounding to a float changes.

These boundaries exist only at the midpoints between two representable values, at the 24th bit of a significand (counting the most significant bit as the 0th bit). But the rounding to a double occurs at the 53rd bit. So rounding to double can cause a value to cross the float rounding boundary only if bits 24 to 53 have specific values, shown in the following cases.

[Somebody should check these; it is easy to make a mistake.]

Case 0:

               Bit 23 24 25-52 53 54…
Original            1  0 11…11  1 anything
Rounded to double   1  1 00…00  0 0… (53 above midpoint: rounds up, carries to higher bits)
Then to float       0  0 00…00  0 0… (24 at midpoint, 23 is odd: rounds up, carries into bit 22, not shown)
Directly to float   1  0 00…00  0 0… (24 below midpoint: rounds down)

Case 1:

               Bit 23 24 25-52 53 54…
Original            0  1 00…00  0 anything except all zeroes
Rounded to double   0  1 00…00  0 0… (53 below midpoint: rounds down)
Then to float       0  0 00…00  0 0… (24 at midpoint, 23 is even: rounds down)
Directly to float   1  0 00…00  0 0… (24 above midpoint: rounds up)

Case 2:

               Bit 23 24 25-52 53 54…
Original            0  1 00…00  1 0…
Rounded to double   0  1 00…00  0 0… (53 at midpoint, 52 is even: rounds down)
Then to float       0  0 00…00  0 0… (24 at midpoint, 23 is even: rounds down)
Directly to float   1  0 00…00  0 0… (24 above midpoint: rounds up)

Case 0 requires 31 bits have specific values, so it occurs one time in 231, assuming values are effectively distributed uniformly. Case 1 is the same except it also requires that a one bit occur anywhere in infinitely many bits, the probability of which is effectively one. Case 2 requires infinitely many bits be zero, so it has a probability of zero. Aesthetically at least, cases 1 and 2 dovetail.

The combined probability of any of these cases occurring is 1 in 230.

So, cases where rounding a double result to float produces a different result than directly calculating a float result are rare.

On top of that, most pow implementations are imperfect. They are not known to return correctly rounded results in all cases. (This is hard to implement.) So you may have imperfect results anyway. Rounding to double and then to float will not make a noticeable difference.

like image 113
Eric Postpischil Avatar answered Feb 23 '23 00:02

Eric Postpischil


You could always write your own little function to do it.

public float power(final float base, final int power) {
    float result = 1;
    for( int i = 0; i < power; i++ ) {
        result *= base;
    }
    return result;
}

EDIT: Some additional testing

As people have pointed out in the comment section, this will return errors if the resulting float proves too large to be stored within a float value.

The following main method:

public static void main(final String[] args) {
    System.out.println( power(Float.MAX_VALUE, 2));
}

gave me the result:

Infinity

Obviously, my solution has its limitations.

EDIT: Further Reading

To avoid the limitation present, I wonder if you could use a double during the calculations, then convert them it a float just before returning. Either by using Math.pow() or altering the code above.

Keep in mind, this may well result in some precision issues which are explained in this other SO post

like image 28
Dan Temple Avatar answered Feb 23 '23 01:02

Dan Temple