Вот мой код:
int f(double x)
{
return isnan(x);
}
Если я #include <cmath>
Я получаю эту сборку:
xorl %eax, %eax
ucomisd %xmm0, %xmm0
setp %al
Это достаточно умно: ucomisd устанавливает флаг четности, если сравнение x с самим собой неупорядочено, что означает, что x равен NAN. затем ЗАД копирует флаг четности в результат (только один байт, следовательно, начальная очистка %eax
).
Но если я #include <math.h>
Я получаю эту сборку:
jmp __isnan
Теперь код не является встроенным, и __isnan
Функция, конечно, не быстрее, чем ucomisd
инструкция, поэтому мы понесли скачок без пользы. Я получаю то же самое, если я компилирую код как C.
Теперь, если я изменю isnan()
позвонить __builtin_isnan()
Я получаю простое ucomisd
инструкция инструкция независимо от того, какой заголовок я включаю, и она работает в Си тоже. Точно так же, если я просто return x != x
,
Итак, мой вопрос, почему C <math.h>
заголовок обеспечивает менее эффективную реализацию isnan()
чем C ++ <cmath>
заголовок? Люди действительно должны использовать __builtin_isnan()
и если да, то почему?
Я тестировал GCC 4.7.2 и 4.9.0 на x86-64 с -O2
а также -O3
оптимизация.
Смотря на <cmath>
для libstdc ++, поставляемой с gcc 4.9, вы получите следующее:
constexpr bool
isnan(double __x)
{ return __builtin_isnan(__x); }
constexpr
функция может быть агрессивно встроена и, конечно, функция просто делегирует работу __builtin_isnan
,
<math.h>
заголовок не использует __builtin_isnan
скорее он использует __isnan
реализация, которая является своего рода долго вставлять здесь, но это строки 430 math.h
на моей машине ™. Поскольку стандарт C99 требует использования макроса для isnan
и др. (раздел 7.12 стандарта C99) «функция» определяется следующим образом:
#define isnan(x) (sizeof (x) == sizeof (float) ? __isnanf (x) \
: sizeof (x) == sizeof (double) ? __isnan (x) \
: __isnanl (x))
Тем не менее, я не вижу причин, почему он не может использовать __builtin_isnan
вместо __isnan
так что я подозреваю, что это недосмотр. Как отмечает Марк Глисс в комментариях, есть соответствующий отчет об ошибке по аналогичной проблеме, используя isinf
вместо isnan
,