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
?
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With