При переводе числа int во float и обратно теряется точность числа
Вопрос на злобу дня освежить знания о числе с плавающей точкой и потренировать перевод этого числа в двоичную систему и обратно.
В документах оракла в пункте 5.1.2 приводится пример с потерей данных числа при переводе его в тип float, а затем обратно в int.
class Test {
public static void main(String[] args) {
int big = 1234567890;
float approx = big;
System.out.println(big - (int)approx); //output -46
}
}
Вопрос - почему именно -46?
Я вручную перевёл число 1234567890 в двоичный вид числа с плавающей точкой. Получилось следующее:
1-ый бит на хранение знака (0), следующие 8 битов на хранение экспоненты, оставшиеся 23 бита на хранение мантиссы. Приступим:
Число 1234567890 в двоичной системе будет 1001001100101100000001011010010. Далее необходимо записать это число в экспонентной форме (т.е. перенести запятую на столько разрядов, чтобы перед ней была только 1 единица). Делаем:
1,001001100101100000001011010010
Мы перенесли запятую 30 раз влево, соответственно наша экспонента будет 30 (+127) = 157.
157 в двоичной системе будет 10011101.
Соответственно наше число в экспонентной форме записи примет такой вид:
Знак / экспонента / мантисса
0 / 10011101 / 00100110010110000000101
Про знак и экспоненту всё понятно, а вот с мантиссой поступают так: отбрасывают первую единицу и пишут оставшиеся 23 числа (т.к. свободно всего 23 бита). Оставшиеся биты, а именно 1010010 просто отбрасываются.
Соответственно при переводе этого числа обратно в десятичную систему нам как раз и не будет хватать этих 7 бит (1010010).
Т.е. наше число примет следующий вид в двоичной системе:
100100110010110000000101 (0000000) - добиваем оставшиеся "потерянные 7 битов" нулями.
Данное число представляет собой в десятичной системе 1234567808 (что на 82 меньше исходного).
Так почему же на выходе в консоли при вычитании чисел мы получаем разницу 46?