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
.