Под потоком с проверкой арифметики с плавающей запятой - PullRequest
2 голосов
/ 25 июня 2019

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

(Exp(-a*a) - Exp(-b*b))*Exp(c)*Exp(d) 

И a, b, c, d также включают некоторые вычисления аналогичного типа.Я могу справиться с двойной ошибкой, получая это неправильно (и возвращая соответствующее сообщение об ошибке или некоторую аналитическую оценку), но если я не обнаруживаю недостаток (например, по разнице экспонент), это приводит к поведению, которое я не могу себе позволить.(Как абсолютные, так и относительные ошибки могут быть огромными, когда эта разница обнуляется, в то время как другие экспоненты очень велики.)

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

Любое решение, которое гарантирует его правильность, даже такое, которое поднимает больше флагов, чем необходимо, хорошо для меня.


Этот вопрос был предложен как дубликат, но «проверка вручную перед каждым умножением» не является для меня особенно полезным решением.

1 Ответ

3 голосов
/ 25 июня 2019

Есть ли что-то похожее на проверенное ключевое слово, которое работает для двойников?

Нет.

Есть ли какой-нибудь способ, которым я могу реализовать проверки вспомогательным способом?

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

Лучшее решение: вы можете подумать о написании библиотеки символической логики.Рассмотрим, например, что произойдет, если вы создадите свой собственный номер:

struct ExpNumber 
{
  public double Exponent { get; }
  public ExpNumber(double e) => Exponent = e;
  public static ExpNumber operator *(ExpNumber x1, ExpNumber x2) => 
    new ExpNumber(x1.Exponent + x2.Exponent);

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

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

...