Действительно ли exp (-1/0.) == 0 удерживается даже с оптимизацией -ffast-math? - PullRequest
0 голосов
/ 17 мая 2018

В соответствии с IEEE-754, следующее

#include <iostream>
#include <cmath>

int main() {
  std::cout << std::exp(-1/0.) << "\n";
  return 0;
}

дает 0 как результат. Причина в том, что -1/0.0 дает -INF, а exp этого дает 0.

Теперь мне нужен мой код для запуска с -ffast-math. Я понимаю, что эта опция делает, в частности, бесконечности не-IEEE-совместимыми . Поэтому я не думаю, что могу положиться на промежуточный результат -INF.

Однако экспоненциальная функция (по крайней мере, математически) очень устойчива для отрицательных аргументов: любое конечное значение < -1e+3 уже дает 0 в качестве результата. Итак, я был бы полностью в порядке, если бы компилятор просто заменил бесконечность большим конечным значением.

По крайней мере, в g++-5.4 это работает надежно, но разумно ли на это полагаться?


Я еще не убежден в комментариях и ответе о том, что исходный код ненадежен, но вот что я решил сделать, чтобы быть уверенным:

#include <iostream>
#include <cmath>
#include <limits>

int main() {
  double a = 0.;   // In practice, this is actually a small, nonnegative,
                   // usually-but-not-always >0 number
  double tiny = 1e-50;
  double b = std::exp(-1/(a+tiny));
  std::cout << b << "\n";
  return 0;
}

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

Я подумал об использовании epsilon вместо tiny, но на самом деле это не лучше выражает намерение. (На самом деле это исказит результаты; на самом деле я хочу выразить a + tiny == a для любого a, для которого определено exp(-1/a).)

1 Ответ

0 голосов
/ 17 мая 2018

Нет, не стоит полагаться на это.Как упоминалось в ответе на вопрос stackoverflow, если вы полагаетесь каким-либо образом на правильность обработки бесконечностей и все еще хотите использовать -ffast-math, вам также следует использовать флаг -fno-finite-math-only.

...