2014-09-26 8 views
42

Ecco il mio codice:Perché GCC implementa isnan() in modo più efficiente per C++ <cmath> rispetto a C <math.h>?

int f(double x) 
{ 
    return isnan(x); 
} 

Se mi #include <cmath> ottengo questa assemblea:

xorl %eax, %eax 
ucomisd %xmm0, %xmm0 
setp %al 

Questa è ragionevolmente intelligente: ucomisd imposta il flag di parità se il confronto di x con se stessa è ordinata, cioè x è NAN. Quindi setp copia il flag di parità nel risultato (solo un singolo byte, quindi il valore iniziale di %eax).

Ma se #include <math.h> ottengo questa assemblea:

jmp  __isnan 

Ora il codice non è in linea, e la funzione __isnan è certamente più veloce le istruzioni del ucomisd, quindi abbiamo subito una salto per alcun beneficio. Ho la stessa cosa se compilo il codice come C.

Ora se cambio la chiamata isnan()-__builtin_isnan(), ho la semplice istruzione ucomisd istruzione, indipendentemente da quale intestazione includo, e funziona in C anche. Allo stesso modo se ho solo return x != x.

Quindi la mia domanda è, perché l'intestazione C <math.h> forniscono una meno efficiente attuazione isnan() di intestazione C++ <cmath>? Le persone si aspettano davvero di usare __builtin_isnan(), e se sì, perché?

Ho testato GCC 4.7.2 e 4.9.0 su x86-64 con l'ottimizzazione -O2 e -O3.

+2

ecco la mia speculazione: pre c99, non esiste una funzione inline in c. nessuna funzione inline significa che le funzioni devono essere invocate da jmp/call (o una sorta di branching). __builtin_isnan non fa parte di c. è probabilmente un intrinseco specifico della piattaforma. – thang

+2

Ma sicuramente un'intestazione di sistema come "" può utilizzare i built-in specifici della piattaforma. –

+1

Sono abbastanza sicuro che 'isnan' userebbe' __builtin_isnan' se possibile. Non vedo perché dovresti chiamarlo manualmente. – Rapptz

risposta

15

Guardando <cmath> per libstdC++ fornito con gcc 4.9 si ottiene questo:

constexpr bool 
    isnan(double __x) 
    { return __builtin_isnan(__x); } 

Una funzione constexpr potrebbe essere aggressivo inline e, naturalmente, la funzione appena delega il lavoro verso __builtin_isnan.

L'intestazione <math.h> non usa __builtin_isnan, piuttosto si utilizza un __isnan attuazione, che è una specie di lunga per incollare qui ma è le linee 430 di math.h sulla mia macchina ™. Poiché lo standard C99 richiede l'uso di una macro per isnan et al (sezione 7.12 dello standard C99) la 'funzione' è definito come segue:

#define isnan(x) (sizeof (x) == sizeof (float) ? __isnanf (x) \ 
    : sizeof (x) == sizeof (double) ? __isnan (x) \ 
    : __isnanl (x)) 

Tuttavia, non vedo alcun motivo per cui non è possibile utilizzare invece __builtin_isnan di __isnan quindi sospetto sia una svista. Come sottolinea Marc Glisse nei commenti, c'è un relevant bug report per un problema simile utilizzando isinf anziché isnan.

+0

in realtà, il bug riguarda isinf. è un problema simile con una funzione diversa, ma non è strettamente lo stesso problema. – thang

+2

Non dimenticare di includere [this] (http://chat.stackoverflow.com/transcript/message/19109073#19109073) dicendo che lo standard * richiede * che siano macro. – Mysticial

+1

Pensi che sarebbe legittimo cambiare '' per dire semplicemente '#define isnan (x) __builtin_isnan (x)'? –

Problemi correlati