Подтвердить что ты не робот

Какие типы чисел представляются в двоичной с плавающей запятой?

Я много читал о поплавках, но все это излишне. Я думаю, что я понял это довольно хорошо, но я хотел бы точно знать только одну вещь:

Я знаю, что фракции формы 1/pow(2,n), с n целым числом, могут быть представлены точно в числах с плавающей запятой. Это означает, что если я добавлю 1/32 к себе 32 миллиона раз, я бы получил ровно 1,000,000.

Как насчет чего-то вроде 1/(32+16)? Это одно над суммой двух степеней два, это работает? Или это работает 1/32+1/16? Вот где я в замешательстве, поэтому, если кто-нибудь сможет прояснить это, я буду признателен.

4b9b3361

Ответ 1

Правило можно суммировать следующим образом:

  • Число может быть представлено точно в двоичном выражении, если простая факторизация знаменателя содержит только 2. (т.е. знаменатель является степенью двух)

Итак, 1/(32 + 16) не представляется в двоичном виде, потому что он имеет коэффициент 3 в знаменателе. Но 1/32 + 1/16 = 3/32 есть.

Тем не менее, существует больше ограничений для представления в типе с плавающей точкой. Например, у вас есть только 53 бит мантиссы в IEEE double, поэтому 1/2 + 1/2^500 не может быть представлен.

Таким образом, вы можете делать сумму степеней-двух, если диапазон экспонентов не превышает более 53 степеней.


Чтобы обобщить это на другие базы:

  • Число может быть точно представлено в базе 10, если простая факторизация знаменателя состоит только из 2 и 5.

  • Рациональное число X может быть точно представлено в базе N, если простая факторизация знаменателя X содержит только простые числа, найденные при факторизации N.

Ответ 2

Конечное число может быть представлено в общем формате двойной точности IEEE 754 тогда и только тогда, когда оно равно M • 2 e для некоторых целых чисел M и e таких, что -2 53 M < 2 53 и -1074 ≤ e ≤ 971.

Для одиночной точности -2 24 M < 2 24 и -149 ≤ e ≤ 104.

Для двойной точности это последствия фактов, что формат двойной точности использует 52 бита для хранения значимости (которая обычно имеет 53 бита из-за неявного 1) и использует 11 бит для хранения экспоненты. 11 бит кодирует числа от 0 до 2047, но 0 и 2047 исключены для специальных целей, а кодированный номер смещен на 1023, поэтому он представляет собой несмещенные показатели от -1022 до 1023. Однако эти несмещенные показатели являются значащими в интервале [1, 2], и эти значения имеют фракции. Чтобы выразить значение как целое число, я скорректировал диапазон экспоненты на 52. Одинарная точность аналогична, с 23 битами для хранения 24-битного значения, 8 бит для экспоненты и смещения 127.

Выражая представляемые числа, используя целое число раз, мощь двух, а не более общее дробное значение, упрощает некоторую теорию чисел и другие рассуждения о свойствах с плавающей запятой. Я использовал его в этом ответе, потому что он позволяет кратко выразить набор представляемых значений.

Ответ 3

Числа с плавающей запятой буквально представлены с помощью формы:

1.m * 2^e

Где 1.m - двоичная дробь, а e - положительное или отрицательное целое число.

Таким образом, вы можете точно представить 1/32 + 1/16, как:

1.1000000 * 2^-4

(1.10 является двоичной дробью, эквивалентной 1.5.) 1/48, однако, не представляется в этом формате.

Ответ 4

Одна точка, еще не упомянутая, состоит в том, что семантически число с плавающей запятой лучше всего рассматривать как представляющее диапазон значений. Диапазон значений имеет очень точно определенную центральную точку, и спецификация IEEE обычно требует, чтобы результатом вычисления с плавающей запятой было число, диапазон которого содержит точку один, будет работать по центральным точкам исходных чисел, но в последовательности:

  double N1 = 0.1;
  float  N2 = (float)N1;
  double N3 = N2;

N2 - однозначное правильное представление с единственной точностью значения, которое было представлено в N1, несмотря на глупое требование использования явного приведения. N3 будет представлять одно из значений, которое может представлять N2 (спецификация языка выбирает значение double, диапазон которого находится по центру в середине диапазона float). Обратите внимание, что хотя N2 представляет значение своего типа, диапазон которого содержит правильное значение, N3 не делает.

Кстати, преобразование числа из строки в float в .net и .net-языках, кажется, проходит промежуточное преобразование в double, что иногда может изменить значение. Например, хотя значение 13571357 представляется как float с одной точностью, значение 13571357.499999999069f округляется до 13571358 (хотя оно явно приближается к 13571357).