При переводе числа 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?