В соответствии с 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)
.)