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

265

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

Что я не понимаю, так это то, почему с математической точки зрения числа, расположенные справа от десятичной запятой, являются более "особыми". что слева?

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

Напротив, если я перемещу десятичное число на одно место в другом направлении, чтобы получить число 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 ...

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

В двоичном формате число 3 представляется как 2 & # xB9; + 2 & # xB0; = 2 + 1. Легко и приятно. Теперь взгляните на 1/3. Как бы вы это представили, используя отрицательные степени 2? Немного поэкспериментируйте, и вы увидите, что 1/3 равна сумме бесконечной последовательности 2 ^ -2 + 2 ^ -4 + 2 ^ -6 + 2 ^ -8 + ..., т.е. не так просто представить точное в двоичном виде. Lars Haugseth
Джон Скит очень хорошо отвечает на вопрос в вашем теле. Единственное, чего не хватает, так это того, что вы на самом деле задаете два разных вопроса. Заголовочный вопрос таков: «Почему десятичные числа не могут быть представлены точно в двоичном формате?» Ответ, они могут быть. Между своим названием и телом вы объединяете идею «двоичного кода»; и идея «представления с плавающей запятой». Плавающая точка - это способ выражения десятичных чисел в фиксированном количестве двоичных цифр за счет точности. Двоичный код - это просто другая основа для подсчета, и он может выражать любое десятичное число, учитывая бесконечное количество цифр. Chris Blackwell
Вы можете найти это полезным, чтобы точно понять, что происходит внутри числа с плавающей запятой:Anatomy of a floating point number. John D. Cook
Этот вопрос кажется не по теме, потому что он касается математики (даже если это математика, связанная с программированием) и будет лучшеMathematics Cole Johnson
Существует несколько систем, которые имеют точное десятичное представление. Это работает так же, как вы описали. Десятичный тип SQL является одним из примеров. Это встроено в языки LISP. Существует несколько коммерческих библиотек и библиотек с открытым исходным кодом для точных десятичных вычислений. Просто для этого нет аппаратной поддержки, и просто большинство языков и аппаратного обеспечения реализуют стандарты IEEE для представления бесконечного количества чисел в 32 или 64 битах. nos

Ваш Ответ

20   ответов
0

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


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

well its the same for floating point(with some distinctions) but the bits represent 2^-n 2^-1=1/2=0.5
2^-2=1/(2*2)=0.25
2^-3=0.125
2^-4=0.0625

Бинарное представление с плавающей точкой:

знак & # xA0; экспонента & # xA0; & # xA0; & # xA0; & # xA0; Фракция (я думаю, что невидимый 1 добавляется к фракции)
B11 & # xA0; & # xA0; B10 B9 B8 & # xA0; & # xA0; & # xA0; B7 B6 B5 B4 B3 B2 B1 B0

4

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

4

(Примечание: я добавлю '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)

или в мантиссе и показателях в двоичном виде:

(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

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

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

1

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

0

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

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

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

Десятичные числа, конечно. Но это только по определению. Вы не можете представить 1/3 в десятичном виде, больше, чем вы можете представить 0,1 в двоичном формате. Любая схема квантования не выполняется для бесконечно большого набора чисел.
3

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

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

1/3 (0.3333...)

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

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

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

Непрерывная доля Пи:

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

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

355/113

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

Но даже с бесконечным числом бит, если вы использовали плавающийbinary Таким образом, вы все равно не сможете точно представить 0,1, точно так же, как вы не можете представить 1/3 точно в десятичном виде даже с бесконечным числом битов.
Десятичные числа, конечно. Но это только по определению. Вы не можете представить 1/3 в десятичном виде, больше, чем вы можете представить 0,1 в двоичном формате. Любая схема квантования не выполняется для бесконечно большого набора чисел.
Но как бы вы представили это в двоичном формате? Например, 15 требует представления 4 битов, а 292 - 9. Как аппаратное обеспечение (или даже программное обеспечение) узнает, где находятся битовые границы между ними? Это компромисс между эффективностью и точностью.
@Jon Это неверно: сinfinite количество десятичных знаков, яcan например, экспресс "одна треть";exactly, Реальная проблема заключается в том, чтоnot physically possible иметь «бесконечное число» десятичных знаков или битов.
4

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

2

В уравнении

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))
4

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

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

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

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

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

Как 0,1 в двоичном виде (0,1 = 0,00011001100110011 .... & lt; - с бесконечным числом "0011")

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

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

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

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

Я говорил о «двоичном представлении (дополнении 2)». Потому что, конечно, использование другого представления может помочь вам представитьsome число с конечным числом элементов (и вам понадобится бесконечное количество элементов для некоторых других)
Вы можете представить 1/3 как саму дробь. Вам не нужно бесконечное количество бит для его представления. Вы просто представляете его как дробь 1/3, вместо результата, взятого 1 и деления его на 3. Несколько систем работают таким образом. Затем вам понадобится способ использовать стандартные операторы / * + - и аналогичные операторы для работы над представлением дробей, но это довольно просто - вы можете выполнять эти операции ручкой и бумагой, а научить компьютер это делать не нужно. большое дело
1

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

0

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

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

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

340

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

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

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

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


Side note to deal with the problem of finite representations:

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

Да, в мире есть 10 видов людей - тех, кто понимает двоичный код, и тех, кто не понимает.
@muusbolla: Нет. Числа, представленные десятичным представлением1 и десятичное представление0.9... (бесконечно повторяющийся9s после десятичной точки) равны. Возможно, самый простой способ убедиться в этом заключается в следующем: Пусть х =0.9..., Обратите внимание, что10x = 9.9...., Следовательно9x = 10x - x = 9.9... - 0.9... = 9 чтобы9x = 9 а такжеx = 1, Есть и другие способы увидеть это, но я считаю, что это самое простое.
Человечество облажается, имея всего более 2 пальцев.
@JonSkeet:Ctrl+Alt+Delete будет выглядеть неловко только с двумя пальцами.
Это чертовски хороший пример, сэр!
9

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

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

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

Кроме того, вопрос был о точном представлении чисел. Иногда точное представление означает много битов. Прелесть нотации в кавычках заключается в том, что Хенер демонстрирует, что в среднем размер представления уменьшается на 31% по сравнению со стандартным 32-битным представлением фиксированной длины.
Эта система обозначений работает, если мы знаем, где начинается и заканчивается цикл. Люди довольно хорошо распознают циклы. Но, в общем, компьютеры не таковы. Чтобы использовать возможность эффективно использовать символ повторения, компьютер должен был бы иметь возможность выяснить, где находятся циклы после выполнения вычисления. Например, для числа 1/3 цикл начинается сразу. Но для числа 1/97 цикл не будет отображаться до тех пор, пока вы не проработаете ответ, по крайней мере, до 96 цифр. (На самом деле вам нужно 96 * 2 + 1 = 193 цифры, чтобы быть уверенным.) Barry Brown
На самом деле, компьютеру совсем не сложно обнаружить цикл. Если вы читаете статью Хенера, он описывает, как определять циклы для различных арифметических операций. Например, в алгоритме деления, который использует повторное вычитание, вы знаете, где начинается цикл, когда вы видите разницу, которую вы видели раньше.
32

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

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

Правильно, я обновил его, чтобы, надеюсь, уточнить, что второй абзац относится к ошибкам, вызванным отдельной проблемой.
Да, это намного лучше :)
Это нисколько не связано с представлением с плавающей запятой. База, которую вы выбираете для своей плавающей запятой, определяет, какие числа могут быть точно представлены. Да, числа с плавающей запятой фиксированного размера всегда будут иметь пределы своей точности, но это основа, которая останавливает многиеdecimal числа точно представимы вbinary с плавающей точкой, а не размер. Возьмите столько бит, сколько вы хотите - вы все равно не сможете точно представить десятичную 0,1 в двоичном виде.
0

Высокий результат ответа выше прибил это.

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

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

15

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

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

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

Больше информации:

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

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

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

Правда, я должен сказать «реальный», а не «с плавающей запятой». Уточню.
Числа с плавающей точкой по определению рациональны.
В этот момент логика становится менее применимой, ИМО - потому что не только мы не можем справиться со всемиreal числа, использующие двоичные числа с плавающей запятой, но мы не можем даже иметь дело со всемиrational цифры (например, 0,1). Другими словами, я не думаю, что это вообще связано с счетностью :)
@ ТМ: Но ОП не пытается представить все действительные числа. Он пытается представить все точноdecimal числа, которые являются подмножествомrational числа, и, следовательно, только счетно бесконечны. Если бы он использовал бесконечный набор битas a decimal floating point type тогда он будет в порядке. Он использует эти биты какbinary тип с плавающей запятой, который вызывает проблемы с десятичными числами.
На самом деле, рациональные числаare счетно бесконечно. Но не каждыйreal число рациональное число. Я, конечно, могу создать последовательность точных десятичных чисел, которая достигнет любого точного десятичного числа, которое вы в конечном итоге захотите мне дать. Это если вам нужно иметь дело сirrational числа, которые вы попадаете в бесконечно бесконечные множества.
1

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


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

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

0

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

@Jon Это неверно: сinfinite количество десятичных знаков, яcan например, экспресс "одна треть";exactly, Реальная проблема заключается в том, чтоnot physically possible иметь «бесконечное число» десятичных знаков или битов.
Но даже с бесконечным числом бит, если вы использовали плавающийbinary Таким образом, вы все равно не сможете точно представить 0,1, точно так же, как вы не можете представить 1/3 точно в десятичном виде даже с бесконечным числом битов.
21

For example, the number 61.0 has an exact binary representation because the integral portion of any number is always exact. But the number 6.10 is not exact. All I did was move the decimal one place and suddenly I've gone from Exactopia to Inexactville. Mathematically, there should be no intrinsic difference between the two numbers -- they're just numbers.

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

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

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

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

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

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

q has only 2s in its prime factorisation

это очевидноalso правда что

q has only 2s and 5s in its prime factorisation

или, другими словами,whenever p/q has a terminating 2-representation, p/q has a terminating 10-representation, Обратное, однако, делаетnot держать - всякий раз, когдаq имеет 5 в своей первичной факторизации, оно будет иметь конечное 10-представление, ноnot завершающее 2-представление. Это0.1 Пример упоминается другими ответами.

Итак, у нас есть ответ на ваш вопрос -because the prime factors of 2 are a subset of the prime factors of 10, all 2-terminating numbers are 10-terminating numbers, but not vice versa. Он составляет не около 61 против 6,1, а около 10 против 2.

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

Этот ответ объясняет лучше, чем сам Джон Скит!
@MichaelGeiser краткий ответ: округление в точке отображения. Что вы думаете0.15 на самом деле (при хранении в двойном формате IEEE) `0.149999999999999994448884876874`. Увидетьjsfiddle.
Итак, почему же «предупреждение (0,15 * 0,15)»? отображать "0,0225"?
@MichaelGeiser схемы для работы с базой 2 меньше, быстрее и более энергоэффективны, чем схемы для работы с базой 10. Сегодня мы могли бы оправдать накладные расходы, но в 1970-х годах, когда устанавливались стандарты, это было большое дело Попытка сделать это без прямой поддержки схем процессора еще хуже, ожидайте разницы в скорости на порядки.
Отличный пример кода! Хотел бы я дать вам голос за это! Мне нужно поиграть с несколькими функциями, чтобы выяснить, где происходит обрезание. Я все еще поражаюсь, что мы на самом деле имеем дело с этим мусором; поскольку люди работают в базовой десятке почти в 100% случаев, а мы используем нецелые числа так часто, что вы думаете, что реализация математики с плавающей запятой по умолчанию справится с этой чепухой.
6

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

BCD является точным представлением DECIMAL, таким образом, "десятичное" часть его имени. Также нет точного десятичного представления 1/3.
БХД не более или менее точны, чем любая другая база. Пример: как вы представляете 1/3 точно в BCD? Вы не можете ".

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