2014-09-26 11 views
42

Oto mój kod:Dlaczego GCC implementuje isnan() bardziej wydajnie dla C++ <cmath> niż C <math.h>?

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

Gdybym #include <cmath> otrzymuję ten montaż:

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

to rozsądnie mądry: ucomisd ustawia flagę parzystości jeśli porównanie xz sobie jest nieuporządkowane, Znaczenie X to NAN. Następnie setp kopiuje flagę parzystości do wyniku (tylko jeden bajt, stąd początkowe usunięcie z %eax).

ale gdybym #include <math.h> otrzymuję ten montaż:

jmp  __isnan 

Teraz kod nie jest inline, a funkcja __isnan pewnością nie szybciej INSTRUKCJA ucomisd, więc ponieśli skok do żadnych korzyści. Mam to samo, gdybym skompilować kod jako C.

Teraz jeśli zmienię wywołanie isnan() do __builtin_isnan(), mam prostą instrukcję ucomisd instrukcji niezależnie od nagłówka I to, i to działa w C też. Podobnie jak ja po prostu return x != x.

Moje pytanie brzmi: dlaczego nagłówek C <math.h> zapewnia mniej wydajną implementację isnan() niż nagłówek C++ <cmath>? Czy ludzie naprawdę powinni używać __builtin_isnan(), a jeśli tak, dlaczego? Przetestowałem GCC 4.7.2 i 4.9.0 na x86-64 z -O2 i -O3.

+2

Oto moja spekulacja: pre c99, nie ma funkcji inline w c. brak funkcji inline oznacza, że ​​funkcje muszą być wywoływane przez jmp/call (lub jakiś rodzaj rozgałęzień). __builtin_isnan nie jest częścią c. to prawdopodobnie specyficzna platforma wewnętrzna. – thang

+2

Ale z pewnością nagłówek systemowy, taki jak ' ', może korzystać z wbudowanych funkcji platformy. –

+1

Jestem prawie pewny, że 'isnan' użyje' __builtin_isnan' jeśli to możliwe. Nie widzę powodu, dla którego musiałbyś zadzwonić ręcznie. – Rapptz

Odpowiedz

15

Patrząc na <cmath> dla libstdC++ dostarczonym z gcc 4.9 można uzyskać w ten sposób:

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

constexpr funkcja może być agresywnie inlined i oczywiście funkcję tylko delegaci prace nad do __builtin_isnan.

Nagłówek <math.h> nie używa __builtin_isnan, raczej wykorzystuje implementację __isnan który jest rodzajem długo wkleić tutaj, ale to linie 430 math.h na moim komputerze ™. Ponieważ standard C99 wymaga użycia makra dla isnan wsp (sekcja 7.12 standardu C99) z „funkcja” jest zdefiniowany następująco:

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

Jednak nie widzę powodu, dlaczego nie można używać zamiast __builtin_isnan z __isnan, więc podejrzewam, że to niedopatrzenie. Jak podkreśla Marc Glisse w komentarzach, istnieje relevant bug report dla podobnego problemu z użyciem isinf zamiast isnan.

+0

w rzeczywistości błąd dotyczy isinf. to podobny problem z inną funkcją, ale nie jest to dokładnie ten sam problem. – thang

+2

Nie zapomnij podać [this] (http://chat.stackoverflow.com/transcript/message/19109073#19109073) mówiąc, że standard * wymaga *, że są makrami. – Mysticial

+1

Czy uważasz, że byłoby uzasadnione zmienić '', aby po prostu powiedzieć '#define isnan (x) __builtin_isnan (x)'? –

Powiązane problemy