Понимание ошибок представления с плавающей точкой;что не так с моим мышлением? - PullRequest
5 голосов
/ 08 июня 2011

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

Как мы знаем, нормальное число с плавающей точкой будет иметь бит знака, показатель степени и мантиссу.Почему, например, 0,1 нельзя точно представить в этой системе;я думаю, что вы положите 10 (1010 в мусорное ведро) на мантиссу и -2 на показатель степени.Насколько я знаю, оба числа могут быть точно представлены в мантиссе и экспоненте.Так почему же мы не можем точно представить 0,1?

Ответы [ 5 ]

8 голосов
/ 08 июня 2011

Если ваш показатель степени десятичный (т. Е. Он представляет 10 ^ X), вы можете точно представить 0,1 - однако большинство форматов с плавающей запятой используют двоичные показатели (то есть они представляют 2 ^ X). Поскольку нет целых чисел X и Y, таких как Y * (2 ^ X) = 0.1, вы не можете точно представить 0,1 в большинстве форматов с плавающей запятой.

Некоторые языки имеют типы с обоими показателями. В C #, например, существует тип данных с точным именем decimal, который является форматом с плавающей запятой с десятичной экспонентой, поэтому он будет поддерживать сохранение числа типа 0,1, хотя имеет и другие необычные свойства: тип decimal может различать между 0.1 и 0.10, и всегда верно, что x + 1 != x для всех значений x.

Однако для наиболее распространенных целей C # также имеет типы float и double с плавающей запятой, которые не могут точно хранить 0,1, поскольку они используют двоичный показатель степени (как определено в IEEE-754). Бинарные типы с плавающей запятой используют меньше памяти, быстрее, потому что их легче реализовать, и для них определено больше операций. В общем случае decimal используется только для финансовых значений, где важно точное представление всех десятичных значений, а хранение, скорость и диапазон операций не имеют значения.

2 голосов
/ 11 июня 2011

Каждое число с плавающей точкой в ​​стандарте IEEE 754, по сути, представляет собой некоторое целое число, умноженное на некоторое целое число, равное двум.Например, 3 представлен 3 * 2 0 , 96 представлен 3 * 2 3 , а 3/16 представлен 3 * 2 -4 .

Нет таких целых чисел x и y, что .1 = x * 2 y , поэтому .1 не может быть точно представлен числом с плавающей запятой.Доказательство: если .1 = x * 2 y , то 10x = 2 -y .2 -y явно положительно, поэтому x положительно.Это также целое число, поэтому 10x делится на 10, поэтому оно делится на 5. Поэтому 2 -y - это степень двойки, которая делится на 5, что явно невозможно.

1 голос
/ 08 июня 2011

Это будет 10 × 2 -1 = 5, а не 0,1.

Обычно это похоже на представление одной трети в базовой десятке: просто невозможно с конечным числом цифр.

Кстати, 10 10 = 1010 2 ≠ 1100 2 .

0 голосов
/ 08 июня 2011

Вы думаете о 1 * 10 ^ -1, который работает для представления десятичного с плавающей точкой , такого как десятичное в C #.Нормальная с плавающей точкой (например, float, double) использует двоичное представление, т. Е. С степенями 2

Обычно двоичные данные используются, поскольку они могут быть более эффективно скомпонованы в битах.Десятичная дробь обычно используется, когда требуется абсолютная десятичная точность, например, при подсчете денег.

...