Почему десятичные числа не могут быть представлены точно в двоичном формате?

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

Я не понимаю, почему с математической точки зрения числа справа от десятичной точки больше "специальные", чем те, что слева?

Например, число 61.0 имеет точное двоичное представление, потому что интегральная часть любого числа всегда точна. Но число 6.10 не является точным. Все, что я сделал, это перемещение десятичного места, и я внезапно перешел из Exactopia в Inexactville. Математически не должно быть внутренней разницы между двумя числами - они просто цифры.

В отличие от этого, если я перемещаю десятичное одно место в другом направлении, чтобы создать номер 610, я все еще в Exactopia. Я могу продолжать двигаться в этом направлении (6100, 610000000, 610000000000000), и они все еще точны, точны и точны. Но как только десятичное число пересекает некоторый порог, цифры больше не точны.

Что происходит?

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

... 1000  100   10    1   1/10  1/100 ...

В двоичном формате они будут:

... 8    4    2    1    1/2  1/4  1/8 ...

На этих числах также нет никаких ограничений. Позиции неограниченно увеличиваются влево и вправо.

Ответ 1

Десятичные числа могут быть представлены точно, если у вас достаточно места - просто не плавающие двоичные числа точек. Если вы используете тип плавающей десятичной точки (например, System.Decimal в .NET), то может быть точно представлено множество значений, которые не могут быть представлены точно в двоичной плавающей запятой.

Посмотрите на это по-другому - в базе 10, с которой вам, вероятно, будет комфортно, вы не можете точно выразить 1/3. Это 0.3333333... (повторяющийся). Причина, по которой вы не можете представить 0,1 в качестве двоичного числа с плавающей запятой, по той же причине. Вы можете точно представлять 3, 9 и 27, но не 1/3, 1/9 или 1/27.

Проблема состоит в том, что 3 - простое число, которое не является фактором 10. Это не проблема, когда вы хотите умножить число на 3: вы всегда можете умножить на целое число, не сталкиваясь с проблемами. Но когда вы делите на число, которое является простым и не является фактором вашей базы, вы можете столкнуться с трудностями (и сделаете это, если попытаетесь разделить 1 на это число).

Хотя 0.1 обычно используется в качестве простейшего примера точного десятичного числа, которое не может быть представлено точно в двоичной плавающей точке, возможно, 0.2 является более простым примером, так как он 1/5 - и 5 - это простое, которое вызывает проблемы между десятичной и двоичной.


Боковое примечание для решения задачи конечных представлений:

Некоторые типы плавающих десятичных точек имеют фиксированный размер, такой как System.Decimal другие, такие как java.math.BigDecimal, "сколь угодно большие", но в какой-то момент они достигнут предела, будь то системная память или теоретический максимальный размер массива, Однако это совершенно отдельный момент для основного ответа. Даже если у вас было действительно произвольно большое количество бит, с которыми вы играли, вы все равно не могли бы представлять десятичные числа 0,1 точно в виде плавающего двоичного представления. Сравните это с другим направлением: с учетом произвольного количества десятичных цифр вы можете точно представлять любое число, которое точно представляется как плавающая двоичная точка.

Ответ 2

Причиной неточности является характер числовых баз. В базе 10 вы не можете точно представлять 1/3. Это становится 0.333... Однако в основании 3 1/3 точно представлено 0,1, а 1/2 - бесконечно повторяющееся десятичное (тризимальное?). Значения, которые могут быть окончательно представлены, зависят от числа уникальных простых факторов основания, поэтому основание 30 [2 * 3 * 5] может представлять больше фракций, чем основание 2 или основание 10. Еще больше для основания 210 [2 * 3 * 5 * 7].

Это отдельная проблема из "ошибки с плавающей запятой". Неточность заключается в том, что несколько миллиардов значений распространяются в гораздо большем диапазоне. Поэтому, если у вас есть 23 бит для значения, вы можете представить только около 8,3 миллионов различных значений. Затем 8-разрядный показатель предоставляет 256 опций для распределения этих значений. Эта схема позволяет получить наиболее точные десятичные знаки вблизи 0, поэтому вы можете почти представить 0,1.

Ответ 3

Например, число 61.0 имеет точное двоичное представление, потому что интегральная часть любого числа всегда точна. Но число 6.10 не является точным. Все, что я сделал, это перемещение десятичного места, и я внезапно перешел из Exactopia в Inexactville. Математически не должно быть внутренней разницы между двумя числами - они всего лишь цифры.

Пусть на мгновение отходят от деталей оснований 10 и 2. Пусть ask - в базе b, какие числа имеют завершающие представления, а какие нет? Мгновенная мысль говорит нам, что число x имеет завершающее b -представление тогда и только тогда, когда существует целое число n такое, что x b^n является целым числом.

Итак, например, x = 11/500 имеет завершающее 10-представление, потому что мы можем выбрать n = 3, а затем x b^n = 22, целое число. Однако x = 1/3 не делает, потому что любой n, который мы выбираем, мы не сможем избавиться от 3.

Этот второй пример побуждает нас думать о факторах, и мы можем видеть, что для любого рационального x = p/q (предполагаемого в младших терминах) мы можем ответить на вопрос, сравнив простые факторизации b и q. Если q имеет простые множители не в простой факторизации b, мы никогда не сможем найти подходящий n, чтобы избавиться от этих факторов.

Таким образом, для базы 10 любой p/q, где q имеет простые множители, отличные от 2 или 5, не будет иметь завершающего представления.

Итак, теперь, возвращаясь к основаниям 10 и 2, мы видим, что любое рациональное с завершающим 10-представлением будет иметь вид p/q точно, когда q имеет только 2 и 5 в своей простой факторизации; и это же число будет иметь завершающее 2-представление, когда q имеет только 2 в своей простой факторизации.

Но один из этих случаев является подмножеством другого! Всякий раз, когда

q имеет только 2 в своей простой факторизации

очевидно, также верно, что

q имеет только 2 и 5 в своей простой факторизации

или, по-другому, , когда p/q имеет завершающее 2-представление, p/q имеет завершающее 10-представление. Обратное, однако, не выполняется - всякий раз, когда q имеет 5 в своей простой факторизации, он будет иметь завершающее 10-представление, но не прерывающее 2-представление. Это пример 0.1, упомянутый другими ответами.

Итак, у нас есть ответ на ваш вопрос - , потому что простые множители 2 являются подмножеством простых множителей 10, все 2-конечные числа являются 10-конечными числами, но не наоборот. Это не примерно 61 против 6.1 - это около 10 против 2.

В качестве заключительной заметки, если какой-то причудой люди использовали (скажем) базу 17, но наши компьютеры использовали базу 5, ваша интуиция никогда бы не была сбита с толку этим - не было бы (ненулевое, нецелое) числа, которые прекратились в обоих случаях!

Ответ 4

Корневая (математическая) причина заключается в том, что когда вы имеете дело с целыми числами, они счетно бесконечны.

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

Однако реальные числа несчетно бесконечны. Вы не можете сказать "дайте мне реальное число в позиции 610000000000000" и верните ответ. Причина в том, что даже между 0 и 1 существует бесконечное количество значений, когда вы рассматриваете значения с плавающей запятой. То же самое справедливо для любых двух чисел с плавающей запятой.

Дополнительная информация:

http://en.wikipedia.org/wiki/Countable_set

http://en.wikipedia.org/wiki/Uncountable_set

Update: Мои извинения, я, кажется, неправильно истолковал этот вопрос. Мой ответ о том, почему мы не можем представлять любую реальную ценность, я не понял, что плавающая точка автоматически классифицируется как рациональная.

Ответ 5

Повторить то, что я сказал в своем комментарии к мистеру Скиту: может представлять 1/3, 1/9, 1/27 или любое рациональное в десятичной нотации. Мы делаем это, добавляя дополнительный символ. Например, строка над цифрами, которые повторяются в десятичном расширении числа. Нам нужно представить десятичные числа в виде последовательности двоичных чисел 1) последовательность двоичных чисел, 2) точка счисления и 3) некоторый другой символ, указывающий повторяющуюся часть последовательности.

Обозначение цитаты Хехнера - это способ сделать это. Он использует символ цитаты для представления повторяющейся части последовательности. Статья: http://www.cs.toronto.edu/~hehner/ratno.pdf и запись в Википедии: http://en.wikipedia.org/wiki/Quote_notation.

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

Ответ 7

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

Ответ 8

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

Ответ 9

(Примечание: я добавлю "b", чтобы указать здесь двоичные числа. Все остальные числа указаны в десятичной форме)

Один из способов думать о вещах - это нечто вроде научной нотации. Мы привыкли видеть числа, выраженные в научной нотации, например, 6.022141 * 10 ^ 23. Числа с плавающей запятой хранятся внутри с использованием аналогичного формата - мантиссы и экспоненты, но с использованием степеней два вместо десяти.

Ваш 61.0 можно переписать как 1.90625 * 2 ^ 5, или 1.11101b * 2 ^ 101b с мантиссой и экспонентами. Чтобы умножить это на десять и (переместить десятичную точку), мы можем сделать:

(1.90625 * 2 ^ 5) * (1.25 * 2 ^ 3) = (2.3828125 * 2 ^ 8) = (1.19140625 * 2 ^ 9)

или in с мантиссой и экспонентами в двоичном формате:

(1.11101b * 2 ^ 101b) * (1.01b * 2 ^ 11b) = (10.0110001b * 2 ^ 1000b) = (1.00110001b * 2 ^ 1001b)

Обратите внимание на то, что мы сделали там, чтобы умножить числа. Мы умножили мантиссы и добавили экспоненты. Затем, поскольку мантисса закончилась больше двух, мы нормализовали результат, нажимая экспонента. Это точно также, когда мы корректируем экспоненту после выполнения операции над числами в десятичной научной нотации. В каждом случае значения, с которыми мы работали, имели конечное представление в двоичном выражении, поэтому значения, выведенные базовыми операциями умножения и сложения, также приводили к значениям с конечным представлением.

Теперь рассмотрим, как мы разделим 61 на 10. Мы начнем с деления мантис, 1.90625 и 1.25. В десятичной форме это дает 1.525, хороший короткий номер. Но что это такое, если мы преобразуем его в двоичный? Мы сделаем это обычным способом - вычитаем самую большую мощность из двух, когда это возможно, так же, как преобразование целочисленных десятичных дробей в двоичный, но мы будем использовать отрицательные степени два:

1.525         - 1*2^0   --> 1
0.525         - 1*2^-1  --> 1
0.025         - 0*2^-2  --> 0
0.025         - 0*2^-3  --> 0
0.025         - 0*2^-4  --> 0
0.025         - 0*2^-5  --> 0
0.025         - 1*2^-6  --> 1
0.009375      - 1*2^-7  --> 1
0.0015625     - 0*2^-8  --> 0
0.0015625     - 0*2^-9  --> 0
0.0015625     - 1*2^-10 --> 1
0.0005859375  - 1*2^-11 --> 1
0.00009765625...

О, о. Теперь у нас проблемы. Оказывается, что 1.90625/1.25 = 1.525, представляет собой повторяющуюся фракцию, выраженную в двоичном выражении: 1.11101b/1.01b = 1.10000110011... b Наши машины имеют только так много бит, чтобы удерживать эту мантиссу, и поэтому они будут округлять фракцию и принять нули за пределами определенной точки. Ошибка, которую вы видите при разделении 61 на 10, - это разница между:

1.100001100110011001100110011001100110011... b * 2 ^ 10b
и, скажем:
1.100001100110011001100110b * 2 ^ 10b

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

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

Ответ 10

Это хороший вопрос.

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

ВСЕ числа могут быть представлены десятичным представлением или с двоичным представлением (2 дополнения). Все они!

НО некоторые (большинство из них) требуют бесконечного количества элементов ( "0" или "1" для двоичной позиции или "0", "1" - "9" для десятичной представление).

Как и 1/3 в десятичном представлении (1/3 = 0,33333333... < - с бесконечным числом "3" )

Подобно 0,1 в двоичном (0,1 = 0,00011001100110011.... < - с бесконечным числом "0011" )

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

И как сказал Джон, 3 - простое число, которое не является фактором 10, поэтому 1/3 не может быть представлено числом конечных элементов в базе 10.

Даже с арифметикой с произвольной точностью система нумерации в базе 2 не может полностью описать 6.1, хотя она может представлять 61.

Для 6.1 мы должны использовать другое представление (например, десятичное представление или IEEE 854, которое допускает базу 2 или base 10 для представления значений с плавающей запятой)

Ответ 11

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

Некоторые примеры:

1/3 (0,33333...)

0; 3

5/9 (0,5555...)

0; 1, 1, 4

10/43 (0,232558139534883720930...)

0; 4, 3, 3

9093/18478 (0.49209871198181621387596060179673...)

0; 2, 31, 7, 8, 5

Здесь существует множество известных способов хранения последовательности целых чисел в памяти.

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

Pi продолжаемая дробь:

3; 7, 15, 1, 292 ...

Завершая последовательность в 1, это дает долю:

355/113

что является прекрасным рациональным приближением.

Ответ 12

В уравнении

2^x = y ;  
x = log(y) / log(2)

Следовательно, мне просто интересно, можем ли мы иметь логарифмическую базовую систему для двоичного типа,

 2^1, 2^0, 2^(log(1/2) / log(2)), 2^(log(1/4) / log(2)), 2^(log(1/8) / log(2)),2^(log(1/16) / log(2)) ........

Это может решить проблему, поэтому, если вы хотите записать что-то вроде 32.41 в двоичном формате, это будет

2^5 + 2^(log(0.4) / log(2)) + 2^(log(0.01) / log(2))

или

2^5 + 2^(log(0.41) / log(2))

Ответ 13

Проблема в том, что вы действительно не знаете, действительно ли число действительно равно 61.0. Рассмотрим это:


float a = 60;
float b = 0.1;
float c = a + b * 10;

Каково значение c? Это не точно 61, потому что b на самом деле нет .1 потому что .1 не имеет точного двоичного представления.

Ответ 14

Здесь есть порог, потому что значение цифры переместилось от целого к нецелому. Чтобы представить 61, вы имеете 6 * 10 ^ 1 + 1 * 10 ^ 0; 10 ^ 1 и 10 ^ 0 - целые числа. 6.1 - 6 * 10 ^ 0 + 1 * 10 ^ -1, но 10 ^ -1 - 1/10, что определенно не является целым числом. То, как вы попадаете в Inexactville.

Ответ 15

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

Ответ 16

Число 61.0 действительно имеет точную операцию с плавающей запятой, но это не так для всех целых чисел. Если вы написали цикл, который добавил его как к числу с плавающей запятой с двойной точностью, так и к 64-битовому целому числу, в конечном итоге вы достигнете точки, где 64-битное целое отлично представляет число, но плавающая точка не делает- потому что не хватает значительных бит.

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

Еще один способ задуматься о том, что, когда вы отмечаете, что 61.0 отлично представимо в базе 10, а смещение десятичной точки вокруг не меняет этого, вы выполняете умножение на десятичные (10 ^ 1, 10 ^ -1). В плавающей точке умножение на две степени не влияет на точность числа. Попробуйте взять 61.0 и делить его на три раза для иллюстрации того, как точное точное число может потерять свое точное представление.

Ответ 18

вы знаете целые числа? каждый бит представляет 2 ^ n


2 ^ 4 = 16
2 ^ 3 = 8
2 ^ 2 = 4
2 ^ 1 = 2
2 ^ 0 = 1

хорошо то же самое для плавающей запятой (с некоторыми отличиями), но биты представляют 2 ^ -n 2 ^ -1 = 1/2 = 0,5
2 ^ -2 = 1/(2 * 2) = 0,25
2 ^ -3 = 0,125
2 ^ -4 = 0,0625

Двоичное представление с плавающей запятой:

sign Exponent   Фракция (я думаю, что невидимая 1 добавляется к фракции)
B11   B10 B9 B8   B7 B6 B5 B4 B3 B2 B1 B0

Ответ 19

Высокий скоринговый ответ выше прибил его.

Сначала вы смешивали базу 2 и базу 10 в своем вопросе, а затем, когда вы помещаете число с правой стороны, которое не делится на базу, вы получаете проблемы. Как 1/3 в десятичном, потому что 3 не переходит в мощность 10 или 1/5 в двоичном формате, которая не переходит в степень 2.

Еще один комментарий, хотя НИКОГДА не используйте равные числа с плавающей запятой, период. Даже если это точное представление, в некоторых системах с плавающей запятой есть некоторые числа, которые могут быть точно представлены более чем одним способом (IEEE плохо об этом, это ужасная спецификация с плавающей запятой, так что ожидайте головные боли). Никакой другой здесь 1/3 не EQUAL к числу на вашем калькуляторе 0.3333333, независимо от того, сколько 3 находится справа от десятичной точки. Это или может быть достаточно близко, но не равно. поэтому вы ожидаете, что что-то вроде 2 * 1/3 не будет равно 2/3 в зависимости от округления. Никогда не используйте равную с плавающей точкой.

Ответ 20

Как мы обсуждали, в арифметике с плавающей запятой десятичная 0,1 не может быть идеально представлена ​​в двоичном формате.

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

Если мы будем использовать двоичное кодированное десятичное представление, как предложил один джентльмен, могли бы мы сохранить числа на сетке?