Java. Как вычисляются диапазоны значений для дробных типов float и double?
Известно, что типы данных float и double занимают 4 и 8 байт в памяти соответственно.
Диапазон значений для типа float: 3.4e-038 - 3.4e+038.
Диапазон значений для типа double: 1.7e-308 - 1.7e+308.
Для меня остаётся загадкой, как вычисляются эти пороговые значения.
Ответы (1 шт):
Числа с плавающей точкой в компьютерной системе представляются экспоненциальной записью: -1^s * M * 2^E, где s - знак мантиссы, M - мантисса, E - экспонента (также порядок или показатель степени). Рассмотрим устройство числа с плавающей точкой на примере типа данных float (ёмкость типов и значения разные, но механизм эквивалентен для double).
Разрядная сетка для типа float состоит из 4-ёх байт (32 бит):
- Старший бит (под номером 31) - знак мантиссы;
- Биты 30 - 23 - экспонента;
- Биты 22 - 0 - мантисса.
Для начала разберёмся с экспонентой.
Поскольку под неё выделено 8 битов, то можно допустить, что количество порядков, с помощью которых можно выразить бинарное число равно 2^8 = 256, т.е. [0; 255]. Однако это не совсем так. Числа с плавающей точкой используют 2 зарезервированных битовых представления экспоненты. Это 00000000, выделенная под беззнаковый 0, который нельзя выразить через экспоненциальную запись, а также 11111111, которая выделена под специальные значения NaN и Infinity (в зависимости от значения мантиссы). Вследствие этого диапазон значений сужается и мы имеем - [1; 254].
Это ещё не всё. Числа с плавающей точкой имеют смещение экпоненты, которое можно вычислить по формуле -1*(2^k - 1), где k - количество разрядов, выделенных под эксопненту. В нашем случае это 8 разрядов и, подставив значение в формулу, мы получим смещение -127. В итоге мы имеем диапазон значений [-126; 127]. Использование такого подхода связано с тем, что устройство числа с плавающей точкой в компьютетрной системе использует механизм "sign magnitude storage", когда число и его знак хранятся отдельно в разрядной сетке.
Теперь мы можем расчитать пороговые значения для порядка числа с плавающей точкой:
- MAX: 2^127 ≈ 1.7e38;
- MIN: 2^-126 ≈ 1.1e-38.
Теперь рассмотрим мантиссу:
- MAX: 1.1...{23 бита}...1 ≈ 2;
- MIN: 1.0...{23 бита}...0 = 1.
Теперь мы можем вывести цельный диапазон для типа данных float, вычеслив произведение мантиссы и экспоненты (пороговые значения будут эквивалентны для положительной и отрицательной оси чисел из-за всё того же "sign magnitude storage"):
- MAX (+/-): 2 * 1.7e38 ≈ 3.4e38;
- MIN (+/-): 1 * 1.1e-38 ≈ 1.1e-38.
Ссылка на видео с пояснениями: How to Calculate Range of Float Variable [ Single Precision ]