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

275
задан Barry Brown 6 July 2009 в 09:55
поделиться

17 ответов

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

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

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

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


Дополнительное примечание, касающееся проблемы конечных представлений:

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

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

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

348
ответ дан 23 November 2019 в 02:11
поделиться

вы ведь знаете целые числа? каждый бит представляет 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

Floating point binary representation:

sign Exponent Fraction(i think invisible 1 is appended to the fraction )
B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0

0
ответ дан 23 November 2019 в 02:11
поделиться

Существует бесконечное количество рациональных чисел и конечное количество битов для их представления. См. http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems .

0
ответ дан 23 November 2019 в 02:11
поделиться

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

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

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

0
ответ дан 23 November 2019 в 02:11
поделиться

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

1
ответ дан 23 November 2019 в 02:11
поделиться

There's a threshold because the meaning of the digit has gone from integer to non-integer. To represent 61, you have 6*10^1 + 1*10^0; 10^1 and 10^0 are both integers. 6.1 is 6*10^0 + 1*10^-1, but 10^-1 is 1/10, which is definitely not an integer. That's how you end up in Inexactville.

1
ответ дан 23 November 2019 в 02:11
поделиться

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


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

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

1
ответ дан 23 November 2019 в 02:11
поделиться

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

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

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

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

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

Как 0,1 в двоичном формате (0,1 = 0,00011001100110011 .. .. <- с бесконечным числом «0011»)

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

4
ответ дан 23 November 2019 в 02:11
поделиться

(Примечание: я добавлю букву «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
b Наши машины имеют только определенное количество битов для хранения этой мантиссы, поэтому они просто округляют дробь и принимают нули после определенной точки. Ошибка, которую вы видите при делении 61 на 10, представляет собой разницу между:

1.100001100110011001100110011001100110011 ... b * 2 ^ 10b
b Наши машины имеют только определенное количество битов для хранения этой мантиссы, поэтому они просто округляют дробь и принимают нули после определенной точки. Ошибка, которую вы видите при делении 61 на 10, представляет собой разницу между:

1.100001100110011001100110011001100110011 ... b * 2 ^ 10b
and, say:
1.100001100110011001100110b * 2^10b

It's this rounding of the mantissa that leads to the loss of precision that we associate with floating point values. Even when the mantissa can be expressed exactly (e.g., when just adding two numbers), we can still get numeric loss if the mantissa needs too many digits to fit after normalizing the exponent.

We actually do this sort of thing all the time when we round decimal numbers to a manageable size and just give the first few digits of it. Because we express the result in decimal it feels natural. But if we rounded a decimal and then converted it to a different base, it'd look just as ugly as the decimals we get due to floating point rounding.

4
ответ дан 23 November 2019 в 02:11
поделиться

По той же причине, что вы не можете точно представить 1/3 в базе 10, вам нужно сказать 0,33333 (3).

4
ответ дан 23 November 2019 в 02:11
поделиться

BCD - Десятичное число с двоичным кодом - представления являются точными. Они не очень компактны, но в данном случае вам придется пойти на компромисс для обеспечения точности.

6
ответ дан 23 November 2019 в 02:11
поделиться

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

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

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

15
ответ дан 23 November 2019 в 02:11
поделиться

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

4
ответ дан 23 November 2019 в 02:11
поделиться

Причина неточности - природа основ счисления. В базе 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 вариантов для распределения этих значений.

33
ответ дан 23 November 2019 в 02:11
поделиться

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

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

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

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

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

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

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

q имеет только 2 s в разложении на простые числа

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

q имеет только 2 s и 5 s в разложении на простые множители

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

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

В заключение, если некоторые причуды использовали (скажем) базу 17, а наши компьютеры использовали базу 5,

23
ответ дан 23 November 2019 в 02:11
поделиться

The high scoring answer above nailed it.

First you were mixing base 2 and base 10 in your question, then when you put a number on the right side that is not divisible into the base you get problems. Like 1/3 in decimal because 3 doesnt go into a power of 10 or 1/5 in binary which doesnt go into a power of 2.

Another comment though NEVER use equal with floating point numbers, period. Even if it is an exact representation there are some numbers in some floating point systems that can be accurately represented in more than one way (IEEE is bad about this, it is a horrible floating point spec to start with, so expect headaches). No different here 1/3 is not EQUAL to the number on your calculator 0.3333333, no matter how many 3's there are to the right of the decimal point. It is or can be close enough but is not equal. so you would expect something like 2*1/3 to not equal 2/3 depending on the rounding. Never use equal with floating point.

0
ответ дан 23 November 2019 в 02:11
поделиться

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

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

Там '

9
ответ дан 23 November 2019 в 02:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: