Упорядочивание операции для максимизации двойной точности

Я работаю над каким-то инструментом, который вычисляет числа, которые в худшем случае могут приблизиться к 1e-25, и сравниваю их вместе на Java. Я, очевидно, использую двойную точность.

Я прочитал в другом ответе, что я не должен ожидать большей точности, чем от 1e-15 до 1e-17, и этот другой вопрос касается повышения точности при упорядочении операций в "лучшем" порядке.

Какие операции с двойной точностью более склонны к потере точности по пути? Должен ли я пытаться работать с числом как можно большим или как можно меньшим? Делать сначала деление перед умножением?

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

Любая информация будет принята с благодарностью!

EDIT: Тот факт, что числа "маленькие" по абсолютной величине (1e-25), не имеет значения, так как значение double может опускаться до 1e-324. Но важно то, что когда они очень похожи (оба в 1e-25), мне приходится сравнивать, скажем, 4,64563824048517606458e-21 с 4,64563824048517606472e-21 (разница в 19-й и 20-й цифрах). При вычислении этих чисел разница настолько мала, что я могу столкнуться с "ошибкой округления", когда остаток заполняется случайными числами.

Возникает вопрос: «Как упорядочить вычисления, чтобы свести к минимуму эту потерю точности?». Это может быть деление перед умножением или сначала сложение.


person Matthieu    schedule 15.06.2013    source источник
comment
Вы читали это? docs.oracle.com/cd/E19957-01/806- 3568/ncg_goldberg.html   -  person John    schedule 15.06.2013
comment
Спасибо, я посмотрю и вернусь к вам, но звучит многообещающе.   -  person Matthieu    schedule 15.06.2013
comment
Часть об отмене - это то, что я искал! Можете ли вы опубликовать это как ответ, чтобы я мог принять его?   -  person Matthieu    schedule 17.06.2013
comment
Рад, что это помогло. Вы можете ответить на свой вопрос и принять свой собственный ответ. Если более поздние пользователи сочтут это полезным, они могут проголосовать как за ваш вопрос, так и за ваш ответ.   -  person John    schedule 17.06.2013


Ответы (2)


Если важно получить правильный ответ, следует использовать BigDecimal. Он медленнее, чем double, но для большинства случаев достаточно быстр. Я не могу вспомнить много случаев, когда вы делаете много вычислений с такими маленькими числами, когда не имеет значения, правильный ли ответ - по крайней мере, с Java.

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

person Vegard    schedule 15.06.2013
comment
Верно. Я просто сравниваю свои результаты с другим приложением, и они совпадают до тех пор, пока я, кажется, не достигну точности double. Если это действительно так, я чувствую себя достаточно хорошо, чтобы остановиться на этом, но если есть способ изменить порядок вычислений, чтобы я не терял (слишком много) точности (например, сначала выполняя деление?), я хотел бы сделай это. - person Matthieu; 15.06.2013

Спасибо @John за указание на очень полную статью. про арифметику с плавающей запятой.

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

Что я запомню из этой статьи:

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

В последнем случае помните, что вычисление (x - y) * (x + y) дает более точные результаты, чем x * x - y * y.

person Matthieu    schedule 20.06.2013