Почему числа с плавающей запятой неточные? - программирование
Подтвердить что ты не робот

Почему числа с плавающей запятой неточные?

Почему некоторые цифры теряют точность при сохранении чисел с плавающей запятой?

Например, десятичное число 9.2 может быть выражено точно как отношение двух десятичных целых чисел (92/10), оба из которых могут быть точно выражены в двоичном (0b1011100/0b1010). Однако такое же соотношение, которое хранится как число с плавающей запятой, никогда не равно 9.2:

32-bit "single precision" float: 9.19999980926513671875
64-bit "double precision" float: 9.199999999999999289457264239899814128875732421875

Как такое простое число может быть "слишком большим" для выражения в 64 бит памяти?

4b9b3361

Ответ 1

В большинстве языков программирования числа с плавающей запятой представлены во многом как научная нотация: с показателем и мантиссой (также называемой значимой), Очень простое число, скажем 9.2, на самом деле является этой дробью:

5179139571476070 * 2 -49

Где показатель степени -49, а мантисса - 5179139571476070. Поэтому невозможно представить некоторые десятичные числа таким образом, что и показатель, и мантисса должны быть целыми числами. Другими словами, все поплавки должны быть целыми числами, умноженными на целую степень 2.

9.2 может быть просто 92/10, но 10 не может быть выражен как 2 n, если n ограничено целыми значениями.


Просмотр данных

Во-первых, несколько функций для просмотра компонентов, которые создают 32- и 64-разрядные float. Гляните на них, если вы только заботитесь о выходе (пример в Python):

def float_to_bin_parts(number, bits=64):
    if bits == 32:          # single precision
        int_pack      = 'I'
        float_pack    = 'f'
        exponent_bits = 8
        mantissa_bits = 23
        exponent_bias = 127
    elif bits == 64:        # double precision. all python floats are this
        int_pack      = 'Q'
        float_pack    = 'd'
        exponent_bits = 11
        mantissa_bits = 52
        exponent_bias = 1023
    else:
        raise ValueError, 'bits argument must be 32 or 64'
    bin_iter = iter(bin(struct.unpack(int_pack, struct.pack(float_pack, number))[0])[2:].rjust(bits, '0'))
    return [''.join(islice(bin_iter, x)) for x in (1, exponent_bits, mantissa_bits)]

У этой функции много сложностей, и это было бы довольно касательной, чтобы объяснить, но если вам интересно, важным ресурсом для наших целей является struct.

Python float - это 64-битное число с двойной точностью. В других языках, таких как C, С++, Java и С#, двойная точность имеет отдельный тип double, который часто реализуется как 64 бита.

Когда мы вызываем эту функцию с нашим примером, 9.2, вот что мы получаем:

>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']

Интерпретация данных

Вы увидите, что я разделил возвращаемое значение на три компонента. Этими компонентами являются:

  • Вход
  • Экспонент
  • Мантисса (также называемая значащим или фракцией)

Знак

Знак хранится в первом компоненте как один бит. Легко объяснить: 0 означает, что float является положительным числом; 1 означает, что он отрицательный. Поскольку 9.2 является положительным, наше знаковое значение 0.

Экспонент

Показатель хранится в среднем компоненте как 11 бит. В нашем случае 0b10000000010. В десятичной форме, которая представляет значение 1026. Причуда этого компонента состоит в том, что вы должны вычесть число, равное 2 (# бит) - 1 - 1, чтобы получить истинную экспоненту; в нашем случае это означает вычитание 0b1111111111 (десятичное число 1023) для получения истинного показателя, 0b00000000011 (десятичное число 3).

Mantissa

Мантисса хранится в третьем компоненте как 52 бит. Однако есть и причуда к этому компоненту. Чтобы понять эту причуду, рассмотрите число в научной нотации, например:

6.0221413x10 23

Мантисса будет 6.0221413. Напомним, что мантисса в научной нотации всегда начинается с одной ненулевой цифры. То же самое справедливо для двоичного кода, за исключением того, что двоичный код имеет только две цифры: 0 и 1. Таким образом, двоичная мантисса всегда начинается с 1! Когда поплавок хранится, 1 в передней части двоичной мантиссы опущен, чтобы сэкономить место; мы должны поместить его обратно в передней части нашего третьего элемента, чтобы получить истинную мантиссу:

1,0010011001100110011001100110011001100110011001100110

Это связано не только с простым добавлением, потому что биты, хранящиеся в нашем третьем компоненте, фактически представляют дробную часть мантиссы, справа от radix точка.

Когда речь идет о десятичных числах, мы "перемещаем десятичную точку" умножая или делим на степени 10. В двоичном случае мы можем сделать то же самое путем умножения или деления на степени 2. Поскольку наш третий элемент имеет 52 бита, мы разделим его на 2 52, чтобы переместить его на 52 места вправо:

0,0010011001100110011001100110011001100110011001100110

В десятичной нотации это то же самое, что делить 675539944105574 на 4503599627370496, чтобы получить 0.1499999999999999. (Это один пример отношения, которое может быть выражено точно в двоичном выражении, но только приблизительно в десятичном значении, более подробно см.: 675539944105574/4503599627370496.)

Теперь, когда мы превратили третий компонент в дробное число, добавление 1 дает истинную мантиссу.

Повторное использование компонентов

  • Знак (первый компонент): 0 для положительного, 1 для отрицательного
  • Экспонент (средний компонент): вычитает 2 (# бит) - 1 - 1, чтобы получить истинную экспоненту
  • Mantissa (последний компонент): разделите на 2 (# бит) и добавьте 1, чтобы получить истинную мантиссу

Вычисление числа

Соединяя все три части вместе, мы получаем это двоичное число:

1.0010011001100110011001100110011001100110011001100110 x 10 11

Что мы можем затем преобразовать из двоичного в десятичный:

1.1499999999999999 x 2 3 (неточно!)

И умножьте, чтобы показать окончательное представление числа, с которого мы начали (9.2), после сохранения в виде значения с плавающей запятой:

9,1999999999999993


Представление в виде фракции

9,2

Теперь, когда мы построили номер, можно восстановить его в простую часть:

1.0010011001100110011001100110011001100110011001100110 x 10 11

Сдвиг мантиссы на целое число:

10010011001100110011001100110011001100110011001100110 x 10 11-110100

Преобразование в десятичное число:

5179139571476070 x 2 3-52

Вычесть экспоненту:

5179139571476070 x 2 -49

Поверните отрицательный показатель в деление:

5179139571476070/2 49

Показатель умножения:

5179139571476070/562949953421312

Что равно:

9,1999999999999993

9.5

>>> float_to_bin_parts(9.5)
['0', '10000000010', '0011000000000000000000000000000000000000000000000000']

Уже вы можете видеть, что мантисса - всего 4 цифры, а затем множество нулей. Но пусть проходит через шаги.

Соберите двоичную научную нотацию:

1,0011 x 10 11

Сдвиг десятичной точки:

10011 x 10 11-100

Вычесть экспоненту:

10011 x 10 -1

Двоичный к десятичному:

19 x 2 -1

Отрицательный показатель деления:

19/2 1

Показатель умножения:

19/2

Равно:

9.5



Дальнейшее чтение

Ответ 2

Это не полный ответ (mhlester уже охватил много хорошей основы, которую я не буду дублировать), но я хотел бы подчеркнуть, насколько представление числа зависит от базы, в которой вы работаете.

Рассмотрим долю 2/3

В доброй базе 10, мы обычно пишем ее как нечто вроде

  • 0,666...
  • 0,666
  • 0,667

Когда мы смотрим на эти представления, мы склонны связывать каждую из них с долей 2/3, хотя только первое представление математически равно фракции. Второе и третье представления/аппроксимации имеют ошибку порядка 0,001, что на самом деле намного хуже, чем ошибка между 9.2 и 9.1999999999999993. На самом деле, второе представление даже не округлено правильно! Тем не менее, у нас нет проблемы с 0,666 в качестве приближения числа 2/3, , поэтому у нас не должно быть проблем с тем, как 9.2 аппроксимируется в большинстве программ. (Да, в некоторых программах это имеет значение.)

Числовые базы

Итак, здесь, где числовые базы являются crutial. Если бы мы пытались представить 2/3 в базе 3, то

(2/3) 10= 0.2 3

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

Чтобы проехать этот пункт домой, давайте посмотрим на 1/2. Вас может удивить, что, хотя это совершенно простое число имеет точное представление в базе 10 и 2, для него требуется повторное представление в базе 3.

(1/2) 10= 0,5 10= 0,1 2= 0.1111... 3

Почему числа с плавающей запятой неточны?

Поскольку часто-времена они аппроксимируют рациональные, которые не могут быть представлены окончательно в базе 2 (цифры повторяются), и вообще они аппроксимируют реальные (возможно, иррациональные) числа, которые не могут быть представлены в конечном числе цифр в любой базе.

Ответ 3

Пока все остальные ответы хороши, все еще остается одна вещь:

Невозможно представить иррациональные числа (например, π, sqrt(2), log(3) и т.д.) точно!

И на самом деле их называют иррациональными. Никакого количества бит-памяти в мире было бы достаточно, чтобы провести хотя бы один из них. Только символическая арифметика способна сохранить свою точность.

Хотя если бы вы ограничили свои математические потребности рациональными числами, то проблема точности становится управляемой. Вам нужно будет хранить пару (возможно очень больших) целых чисел a и b для хранения числа, представленного дроби a/b. Вся ваша арифметика должна быть сделана на дроби, как в математике в старших классах (например, a/b * c/d = ac/bd).

Но, конечно, вы столкнулись бы с такими же проблемами, когда задействуются pi, sqrt, log, sin и т.д.

TL; DR

Для аппаратной ускоренной арифметики может быть представлено лишь ограниченное количество рациональных чисел. Каждое не представимое число аппроксимируется. Некоторые числа (т.е. Иррациональные) никогда не могут быть представлены независимо от системы.

Ответ 4

Существует бесконечно много действительных чисел (так много, что вы не можете их перечислить), и существует бесконечно много рациональных чисел (их можно перечислить).

Представление с плавающей запятой является конечным (как и все в компьютере), поэтому неизбежно представить множество много-много чисел. В частности, только 64-битные значения позволяют различать только 18,446,744,073,709,551,616 различных значений (что ничто по сравнению с бесконечностью). Со стандартным соглашением 9.2 не является одним из них. Те, которые могут иметь форму m.2 ^ e для некоторых целых чисел m и e.


Вы можете придумать другую систему нумерации, например, на основе 10, где 9.2 будет иметь точное представление. Но другие цифры, скажем 1/3, все равно невозможно представить.


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

Ответ 5

Почему мы не можем представить 9.2 в двоичной с плавающей запятой?

Номера с плавающей запятой (немного упрощают) систему позиционного нумерации с ограниченным числом цифр и подвижной точкой счисления.

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

Основными факторами 10 являются 5 и 2, поэтому в базе 10 мы можем представить любую долю вида a/(2 b 5 c).

С другой стороны, единственным простым фактором 2 является 2, поэтому в базе 2 мы можем представить только дробные числа вида a/(2 b)

Почему компьютеры используют это представление?

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

Конечно, можно было бы определить формат фракции с (например) 32-битным числителем и 32-битным знаменателем. Он мог бы представлять числа, которые не могли бы выполнять с плавающей точкой двойной точности IEEE, но в равной степени было бы много чисел, которые могут быть представлены в плавающей точке с двойной точностью, которые не могут быть представлены в таком формате фракции фиксированного размера.

Однако большая проблема заключается в том, что такой формат является болью для проведения расчетов. По двум причинам.

  1. Если вы хотите иметь ровно одно представление каждого числа, то после каждого расчета вам нужно уменьшить долю до ее младших членов. Это означает, что для каждой операции вам в основном нужно выполнить наибольший общий делитель.
  2. Если после вашего расчета вы получите непредсказуемый результат, потому что числитель или знаменатель вам нужно найти ближайший представимый результат. Это нетривиальное.

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

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

Ответ 6

Попробуй это

DecimalFormat decimalFormat = new DecimalFormat("#.##");
String.valueOf(decimalFormat.format(decimalValue))));

' decimalValue ' - ваша ценность для конвертации.