Хорошее значение дозорного значения для double, если предпочитаете использовать -ffast-math

Так как опция gcc -ffast-math эффективно отключает NaN и -/+inf, я ищу, возможно, следующий лучший вариант для представления NaN в критическом критически важном математическом коде. В идеале значение дозорного сигнала, если оно работает (add, mul, div, sub и т.д.), Даст значение дозорного значения, поскольку NaN будет делать, но я сомневаюсь, что это было бы возможно, так как я думаю, что NaN - единственное значение, которое выполняет это. -0.0 может оказаться неприемлемым, поскольку он также отключен в -ffast-math и может предотвратить определенные оптимизации, такие как (x+0.0) и т.д.

Возможно, мой вопрос скорее должен быть, есть ли способ использовать NaN или какой-либо другой "специальный двойной", позволяя при этом разрешать много математических оптимизаций без разбивки?

Система Linux/x64, gcc 4.8.1.

Ответ 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.

Ответ 2

Для isnan и isinf, приведенных выше, он должен быть 0xffe0000000000000ull вместо 0xff70000000000000ull.