Ответ 1
Если вы ищете значение, которое будет распространяться арифметическими операциями, NaN
по-прежнему доступен с опцией -ffast-math
. Проблема лежит где-то в другом месте. С помощью -ffast-math
некоторые операции могут быть удалены из вычислений из-за оптимизации, а затем нет возможности гарантировать NaN
или любое другое значение будет распространяться.
Например, следующее с установкой -ffast-math
приведет к сложной записи 0.0
в n
, и для n
нет специального значения, которое защитит его.
float n = NAN;
n *= 0.0;
Одна вещь, которую вы можете сделать, - использовать -fno-finite-math-only -ftrapping-math
с -ffast-math
, как сказал Шафик Ягмур. А другой, если есть только несколько мест, где вы ожидаете плохого значения, вы можете проверить его самостоятельно, поставив тесты точно в этих точках.
Последний вариант, который я могу думать - если вам действительно нужна оптимизация, - это вручную ввести значения NaN
(и, возможно, inf
) в вычисление и проверить, как долго он распространяется. Затем в тех местах, где распространение прекращается, проверьте наличие NaN
(inf
). - Это небезопасный метод, поскольку я не уверен на сто процентов, может -ffast-math
включать условный поток операций. Если это возможно, есть значительный шанс, это решение будет недействительным. Таким образом, это рискованно, и, если его выбрали, требуется очень тяжелое тестирование, охватывающее все ветки вычислений.
Обычно я бы скорее против последнего решения, но на самом деле есть шанс, значения NaN
(inf
) будут распространяться, хотя все вычисление или почти целые, поэтому он может дать производительность, которую вы ищете, Поэтому вы можете рискнуть.
Проверяя NaN
с помощью -ffast-math
, вы можете сделать, как сказал Шафик Ягмур,
inline int isnan(float f)
{
union { float f; uint32_t x; } u = { f };
return (u.x << 1) > 0xff000000u;
}
и для double
с
inline int isnan(double d)
{
union { double d; uint64_t x; } u = { d };
return (u.x << 1) > 0xff70000000000000ull;
}
Проверка inf
будет
inline int isinf(float f)
{
union { float f; uint32_t x; } u = { f };
return (u.x << 1) == 0xff000000u;
}
inline int isinf(double d)
{
union { double d; uint64_t x; } u = { d };
return (u.x << 1) == 0xff70000000000000ull;
}
Вы также можете объединить isnan
и isinf
.