Арифметика с плавающей запятой = какова наихудшая точность / разница между десятичным и двоичным числами?

как всем известно decimal fractions (например, 0.1), при сохранении как floating point (например, double или float) будет внутренне представлен в «двоичном формате» (IEEE 754). А некоторые десятичные дроби не могут быть напрямую представлены в двоичном формате.

Чего я не понял, так это точности этого "преобразования":

1.) Сама по себе плавающая точка может иметь точность (то есть "значимую")?

2.) Но также преобразование из десятичной дроби в двоичную дробь имеет потерю точности?

Вопрос:

Какова наихудшая потеря точности (для "всех" возможных десятичных дробей) при преобразовании десятичных дробей в дроби с плавающей запятой?

(Причина, по которой я хочу это знать, заключается в том, что при сравнении десятичных дробей с двоичными / с плавающей запятой мне нужно учитывать точность ... чтобы определить, идентичны ли обе цифры. И я хочу, чтобы эта точность была максимально точной / точной по возможности (decimal fraction == binary fraction +/- precision)

Пример (только гипотетический)

0,1 dec => 0,10000001212121212121212 (binary fraction double) => precision loss 0,00000001212121212121212
0,3 dec => 0,300000282828282 (binary fraction double) => precision loss  0,000000282828282

person Markus    schedule 24.08.2011    source источник
comment
Это абсолютная разница или разница в процентах? В вашем примере показаны абсолютные различия, но в некоторых ситуациях может иметь смысл найти ситуацию с наибольшей процентной разницей.   -  person Delan Azabani    schedule 24.08.2011
comment
привет Делан, очень хорошее замечание. может быть, потеря точности в процентах была бы более актуальной?   -  person Markus    schedule 24.08.2011
comment
Избегайте множественных вопросительных знаков. Достаточно одного.   -  person user unknown    schedule 24.08.2011


Ответы (5)


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

Верн Паксон и Уильям Кахан. Программа для тестирования десятично-двоичного преобразования IEEE. 22 мая 1991 г. http://www.icir.org/vern/papers/testbase-report.pdf

person njuffa    schedule 24.08.2011

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

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

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

person Arafangion    schedule 24.08.2011

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

В большинстве случаев значение с плавающей запятой в вычислениях требуется два раза: когда это денежная величина, а когда нет. Последний может варьироваться от ввода от кодировщика на вращающемся валу до положения в виртуальном пространстве для передачи в графический движок. Нет проблем с тем, чтобы дробное значение было в двоичном формате, потому что это действительно дробное значение. Отчасти поэтому много лет назад FPU стали популярными для 3D-графики.

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

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

person staticsan    schedule 24.08.2011
comment
К сожалению, с плавающей запятой проблема еще хуже. Обычно у вас есть формат экспоненты знак * основание ^, все из которых находятся в двоичном формате. - person Arafangion; 24.08.2011

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

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

1.0000000000000001110223024625156540423631668090820312

(Это почти бесконечно меньше, чем 1 + 2 ^ -53).

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

Конечно, если число выходит за пределы диапазона представимых значений (либо из-за того, что оно слишком велико, либо слишком мало), вся точность теряется. Преобразование, скажем, 1e400 в double дает infinity; от нашего фактического вклада не осталось и следа. Точно так же преобразование 1e-400 в double дает ноль.

person Stephen Canon    schedule 24.08.2011

Чем больше становится число, тем выше может быть потеря точности (но это может быть именно ваш номер, который вы укажете).

В java вы храните не только очень маленькие числа как float или double, но и очень большие числа, например 9 * 10 ^ 105.

И я хочу, чтобы эта точность была максимально точной / точной.

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

Вас интересует только абсолютная точность или относительная точность?

сравните разницу в точности:

a = 100000000000000,0000000000000001 
b = 100000000000000,0000000000000002

layoutHonkyTonkA= 0,0000000000000001 
layoutHonkyTonkB= 0,0000000000000002

Разница в абсолютной точности такая же, но разница в относительной точности очень разная.

person user unknown    schedule 24.08.2011