Поскольку числа с плавающей запятой представляют собой систему счисления с основанием-2, то невозможно представить 0.24F
непосредственно как то же самое, что невозможно представить 1/3
в десятичной системе без повторяющегося десятичного периода , т. Е. 1/3=0.3333...
или 0.(3)
.
Таким образом, число с плавающей запятой 0.24F
при печати в десятичном представлении отображается как 0.23
с изменением из-за округления:
println(0.24F) => 0.23999999463558197021484375
, а 0.25F
может быть показан непосредственно:
println(0.25F) => 0.25
Но как я могу определить, что число является точно представимым?
isExactFloat(0.25F) ==> true
isExactFloat(0.24F) ==> false
Может быть, в Java API уже есть какая-то функция для этого?
UPD Вот код, который показывает числа с плавающей точкой в диапазоне [-4, 4] с их внутренним представлением:
public class FloatDestructure {
public static void main(String[] args) {
BigDecimal dec = BigDecimal.valueOf(-4000L, 3);
BigDecimal incr = BigDecimal.valueOf(1L, 3);
for (int i = 0; i <= 8000; i++) {
double dbl = dec.doubleValue();
floatDestuct(dbl, dec);
dec = dec.add(incr);
}
}
static boolean isExactFloat(double d) { return d == (float) d; }
static void floatDestuct(double val, BigDecimal dec) {
float value = (float) val;
int bits = Float.floatToIntBits(value);
int sign = bits >>> 31;
int exp = (bits >>> 23 & ((1 << 8) - 1)) - ((1 << 7) - 1);
int mantissa = bits & ((1 << 23) - 1);
float backToFloat = Float.intBitsToFloat((sign << 31) | (exp + ((1 << 7) - 1)) << 23 | mantissa);
boolean exactFloat = isExactFloat(val);
boolean exactFloatStr = Double.toString(value).length() <= 7;
System.out.println(dec.toString() + " " + (double) val + " " + (double) value + " sign: " + sign + " exp: " + exp + " mantissa: " + mantissa + " " + Integer.toBinaryString(mantissa) + " " + (double) backToFloat + " " + exactFloat + " " + exactFloatStr);
}
}
Когда мантисса равна нулю, тогда число с плавающей точкой определенно точно.Но в других случаях, таких как -0.375
или -1.625
, это не так ясно.