sqr c++
¿Por qué GCC implementa isnan() de manera más eficiente para C++<cmath> que C<math.h>? (1)
Si mira <cmath> para libstdc ++ incluido con gcc 4.9, obtendrá esto:
constexpr bool
isnan(double __x)
{ return __builtin_isnan(__x); }
Una función constexpr podría estar constexpr línea y, por supuesto, la función simplemente delega el trabajo en __builtin_isnan .
El <math.h> no usa __builtin_isnan , sino que usa una implementación __isnan que es algo largo de pegar aquí, pero son líneas 430 de math.h en mi máquina ™. Dado que el estándar C99 requiere el uso de una macro para isnan y otros (sección 7.12 del estándar C99), la ''función'' se define de la siguiente manera:
#define isnan(x) (sizeof (x) == sizeof (float) ? __isnanf (x) /
: sizeof (x) == sizeof (double) ? __isnan (x) /
: __isnanl (x))
Sin embargo, no veo ninguna razón por la cual no pueda usar __builtin_isnan lugar de __isnan así que sospecho que es un descuido. Como señala Marc Glisse en los comentarios, hay un sourceware.org/bugzilla/show_bug.cgi?id=15367 para un problema similar con isinf lugar de isnan .
Aquí está mi código:
int f(double x)
{
return isnan(x);
}
Si #include <cmath> obtengo esta asamblea:
xorl %eax, %eax
ucomisd %xmm0, %xmm0
setp %al
Esto es razonablemente inteligente: ucomisd establece la bandera de paridad si la comparación de x con ella misma está desordenada, lo que significa que x es NAN. Luego, setp copia el indicador de paridad en el resultado (solo un byte único, de ahí el inicial vacío de %eax ).
Pero si #include <math.h> obtengo esta asamblea:
jmp __isnan
Ahora el código no está en línea, y la función __isnan ciertamente no es más rápida que la instrucción ucomisd , por lo que hemos incurrido en un salto sin ningún beneficio. Obtengo lo mismo si compilo el código como C.
Ahora si cambio la llamada de __builtin_isnan() a __builtin_isnan() , obtengo la instrucción simple de instrucción ucomisd independientemente del encabezado que incluya, y también funciona en C. Del mismo modo, si acabo de return x != x
Entonces mi pregunta es, ¿por qué el encabezado C <math.h> proporciona una implementación menos eficiente de isnan() que el encabezado C ++ <cmath> ? ¿Se espera realmente que la gente use __builtin_isnan() y, de ser así, por qué?
Probé GCC 4.7.2 y 4.9.0 en x86-64 con optimización -O2 y -O2 .