Арифметика с плавающей точкой = Какая наихудшая точность / разница от Dec до Binary? - PullRequest
5 голосов
/ 24 августа 2011

как все знают 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

Ответы [ 5 ]

4 голосов
/ 24 августа 2011

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

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

3 голосов
/ 24 августа 2011

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

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

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

1 голос
/ 24 августа 2011

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

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

1.0000000000000001110223024625156540423631668090820312

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

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

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

1 голос
/ 24 августа 2011

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

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

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

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

0 голосов
/ 24 августа 2011

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

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

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

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

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

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

a = 100000000000000,0000000000000001 
b = 100000000000000,0000000000000002

layoutHonkyTonkA= 0,0000000000000001 
layoutHonkyTonkB= 0,0000000000000002

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

...