Warum implementiert GCC isnan() effizienter für C++ als C ?

Lesezeit: 3 Minuten

Benutzeravatar von John Zwinck
Johannes Zwinck

Hier ist mein Code:

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

Wenn ich #include <cmath> Ich bekomme diese Baugruppe:

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

Das ist einigermaßen clever: ucomisd setzt das Parity-Flag, wenn der Vergleich von x mit sich selbst unsortiert ist, also x NAN ist. Dann Einst kopiert das Parity-Flag in das Ergebnis (nur ein einzelnes Byte, daher das anfängliche Löschen von %eax).

Aber wenn ich #include <math.h> Ich bekomme diese Baugruppe:

jmp     __isnan

Jetzt ist der Code nicht inline, und die __isnan schneller ist die funktion sicherlich nicht ucomisd Anweisung, also haben wir einen Sprung ohne Nutzen angefallen. Ich bekomme das gleiche, wenn ich den Code als C kompiliere.

Wenn ich jetzt die ändere isnan() Aufruf __builtin_isnan()ich verstehe das einfach ucomisd Anweisung Anweisung unabhängig davon, welchen Header ich einfüge, und es funktioniert auch in C. Ebenso wenn ich gerade return x != x.

Meine Frage ist also, warum C <math.h> Header bieten eine weniger effiziente Implementierung von isnan() als C++ <cmath> Header? Wird von den Menschen wirklich erwartet, dass sie verwenden __builtin_isnan()und wenn ja, warum?

Ich habe GCC 4.7.2 und 4.9.0 auf x86-64 mit getestet -O2 und -O3 Optimierung.

  • Hier ist meine Spekulation: Vor c99 gibt es keine Inline-Funktion in c. keine Inline-Funktion bedeutet, dass Funktionen von jmp/call (oder einer Art Verzweigung) aufgerufen werden müssen. __builtin_isnan ist nicht Teil von c. es ist wahrscheinlich eine plattformspezifische Eigenart.

    – Ding

    26. September 2014 um 5:58 Uhr


  • Aber sicherlich ein Systemheader wie <math.h> können plattformspezifische integrierte Funktionen verwenden.

    – John Kugelmann

    26. September 2014 um 6:01 Uhr

  • Ich bin ziemlich sicher isnan würde benutzen __builtin_isnan wenn möglich. Ich sehe keinen Grund, warum Sie es manuell aufrufen müssten.

    – Raptz

    26. September 2014 um 6:01 Uhr

  • Als C99 auftauchte, dachte vielleicht niemand daran, zurück zu gehen und isnan zu aktualisieren

    – Ding

    26. September 2014 um 6:04 Uhr

  • sourceware.org/bugzilla/show_bug.cgi?id=15367

    – Marc Glisse

    26. September 2014 um 6:08 Uhr

Anschauen <cmath> für libstdc++, das mit gcc 4.9 ausgeliefert wird, erhalten Sie Folgendes:

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

EIN constexpr Funktion könnte aggressiv inliniert werden und natürlich delegiert die Funktion die Arbeit einfach an __builtin_isnan.

Das <math.h> Kopfzeile wird nicht verwendet __builtin_isnansondern verwendet ein __isnan Implementierung, die etwas lang ist, um sie hier einzufügen, aber es sind Zeilen 430 von math.h auf meiner Maschine™. Da der C99-Standard die Verwendung eines Makros für isnan et al (Abschnitt 7.12 des C99-Standards) wird die „Funktion“ wie folgt definiert:

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

Ich sehe jedoch keinen Grund, warum es nicht verwendet werden kann __builtin_isnan Anstatt von __isnan daher vermute ich ein Versehen. Wie Marc Glisse in den Kommentaren betont, gibt es eine entsprechenden Fehlerbericht für ein ähnliches Problem mit isinf Anstatt von isnan.

  • eigentlich handelt es sich bei dem Fehler um isinf. Es ist ein ähnliches Problem mit einer anderen Funktion, aber es ist nicht genau das gleiche Problem.

    – Ding

    26. September 2014 um 6:19 Uhr


  • Vergessen Sie nicht, diesen Spruch zum Standard zu machen erfordert dass sie Makros sind.

    – Mystisch

    26. September 2014 um 6:20 Uhr

  • Glauben Sie, dass es legitim wäre, sich zu ändern? <math.h> einfach sagen #define isnan(x) __builtin_isnan(x)?

    – Johannes Zwinck

    26. September 2014 um 6:38 Uhr


  • @JohnZwinck Ja. Ich kann mir keine Gründe vorstellen, warum es nicht gültig sein sollte.

    – Raptz

    26. September 2014 um 6:39 Uhr

  • Für gcc wäre es gültig. __builtin_isnan ist nicht auf jedem Compiler vorhanden.

    – Ding

    26. September 2014 um 6:51 Uhr

1406450cookie-checkWarum implementiert GCC isnan() effizienter für C++ als C ?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy