Warum sind die schnellen Ganzzahltypen schneller als die anderen Ganzzahltypen?

107

In ISO / IEC 9899: 2018 (C18) ist dies unter 7.20.1.3 angegeben:

7.20.1.3 Schnellste Ganzzahltypen mit minimaler Breite

1 Jeder der folgenden Typen bezeichnet einen Integer-Typ, der normalerweise am schnellsten ist 268), um mit allen Integer-Typen zu arbeiten, die mindestens die angegebene Breite haben.

2 Der typedef-Name int_fastN_tbezeichnet den am schnellsten vorzeichenbehafteten Integer-Typ mit einer Breite von mindestens N. Der typedef-Name uint_fastN_tbezeichnet den schnellsten vorzeichenlosen Integer-Typ mit einer Breite von mindestens N.

3 Folgende Typen sind erforderlich:

int_fast8_t, int_fast16_t, int_fast32_t, int_fast64_t, uint_fast8_t, uint_fast16_t, uint_fast32_t,uint_fast64_t

Alle anderen Arten dieses Formulars sind optional.


268) Es ist nicht garantiert, dass der angegebene Typ für alle Zwecke am schnellsten ist. Wenn die Implementierung keine eindeutigen Gründe für die Auswahl eines Typs gegenüber einem anderen hat, wählt sie einfach einen ganzzahligen Typ aus, der die Anforderungen an Signatur und Breite erfüllt.


Es wird jedoch nicht angegeben, warum diese "schnellen" Ganzzahltypen schneller sind.

  • Warum sind diese schnellen Ganzzahltypen schneller als die anderen Ganzzahltypen?

Ich habe die Frage mit C ++ markiert, da die schnellen Ganzzahltypen auch in C ++ 17 in der Header-Datei von verfügbar sind cstdint. Leider gibt es in ISO / IEC 14882: 2017 (C ++ 17) keinen solchen Abschnitt über ihre Erklärung; Ich hatte diesen Abschnitt ansonsten im Textkörper der Frage implementiert.


Information: In C werden sie in der Header-Datei von deklariert stdint.h.

RobertS unterstützt Monica Cellio
quelle
24
Der entscheidende Punkt hierbei ist, dass diese ganzzahligen Typen keine separaten, magisch schnelleren Typen sind. Sie sind nur Aliase für den normalen vorhandenen Typ, der für diesen Vorgang auf diesem Computer am schnellsten ist.
mtraceur
3
Der Compiler gibt CPU-Operations-Opcodes aus, um Speicherorte und Register bestimmter Größen zu laden, zu speichern, zu maskieren und zu ändern. Das ist alles, was die CPU sieht. Das Betriebssystem hat überhaupt nichts damit zu tun. Es ist alles, was der Compiler tut, genau so, als hätten Sie das angegebene Typedef selbst angegeben. (Ich nehme an, ein Compiler darf es intern anders verarbeiten - vielleicht effizienter, wenn das möglich ist - als ein Benutzer typedef, solange es keinen sichtbaren Unterschied im Verhalten gibt.)
Peter - Monica wieder herstellen
1
@ RobertS-ReinstateMonica Um genau zu sein, sind diese "Aliase" nur typedefAussagen. In der Regel erfolgt dies auf der Ebene der Standardbibliothek. Natürlich sind die C - Standard legt keine wirkliche Beschränkung auf das, was sie typedefzu - so zum Beispiel eine typische Implementierung ist , um int_fast32_teine typedefvon intauf einem 32-Bit - System, sondern eine hypothetische Compiler könnte zum Beispiel eine Implementierung __int_fastintrinsischen Typ und versprechen etwas Phantasie zu tun Optimierungen, um von Fall zu Fall den schnellsten Maschinentyp für Variablen dieses Typs auszuwählen, und dann könnte die Bibliothek genau typedefdas tun.
mtraceur
1
@ RobertS-ReinstateMonica Ja, stimmt. Sie erhalten Programme mit maximaler Leistung mit architekturspezifischen Kompilierungsflags, wodurch die Binärdatei weniger portabel wird.
Peter - Monica
1
@ RobertS-ReinstateMonica Es wird auf der Plattform, für die es kompiliert wurde , am effizientesten sein , nicht unbedingt auf .
HABO

Antworten:

152

Stellen Sie sich eine CPU vor, die nur 64-Bit-Arithmetikoperationen ausführt. Stellen Sie sich nun vor, wie Sie eine vorzeichenlose 8-Bit-Addition auf einer solchen CPU implementieren würden. Es würde notwendigerweise mehr als eine Operation erfordern, um das richtige Ergebnis zu erzielen. Auf einer solchen CPU sind 64-Bit-Operationen schneller als Operationen auf anderen ganzzahligen Breiten. In dieser Situation Xint_fastY_tkönnte alles vermutlich ein Alias ​​vom 64-Bit-Typ sein.

Wenn eine CPU schnelle Operationen für schmale Ganzzahltypen unterstützt und daher ein breiterer Typ nicht schneller als ein schmalerer Typ ist, ist dies kein Xint_fastY_tAlias ​​des breiteren Typs, der zur Darstellung aller Y-Bits erforderlich ist.

Aus Neugier habe ich die Größe einer bestimmten Implementierung (GNU, Linux) auf einigen Architekturen überprüft. Diese sind nicht für alle Implementierungen auf derselben Architektur gleich:

┌────╥───────────────────────────────────────────────────────────┐
 Y     sizeof(Xint_fastY_t) * CHAR_BIT                         
    ╟────────┬─────┬───────┬─────┬────────┬──────┬────────┬─────┤
     x86-64  x86  ARM64  ARM  MIPS64  MIPS  MSP430  AVR 
╞════╬════════╪═════╪═══════╪═════╪════════╪══════╪════════╪═════╡
 8   8       8    8      32   8       8     16      8   
 16  64      32   64     32   64      32    16      16  
 32  64      32   64     32   64      32    32      32  
 64  64      64   64     64   64      64    64      64  
└────╨────────┴─────┴───────┴─────┴────────┴──────┴────────┴─────┘

Beachten Sie, dass Operationen an größeren Typen zwar schneller sein können, diese Typen jedoch auch mehr Speicherplatz im Cache beanspruchen und ihre Verwendung daher nicht unbedingt zu einer besseren Leistung führt. Darüber hinaus kann man nicht immer darauf vertrauen, dass die Implementierung überhaupt die richtige Wahl getroffen hat. Wie immer ist eine Messung erforderlich, um optimale Ergebnisse zu erzielen.


Screenshot der Tabelle für Android-Benutzer:

Screenshot der obigen Tabelle

(Android hat keine Box-Zeichen in der Mono-Schriftart - ref )

Eerorika
quelle
Kommentare sind nicht für eine ausführliche Diskussion gedacht. Dieses Gespräch wurde in den Chat verschoben .
Samuel Liew
@RobertSsupportsMonicaCellio Nr. "Nicht für alle Architekturen gleich" ist ebenfalls wahr, wird jedoch aus den angezeigten Daten sofort ersichtlich, sodass ich es nicht für erforderlich halte, das Offensichtliche anzugeben. Ich habe nur Werte aus einer Implementierung gezeigt, und tatsächlich haben andere unterschiedliche Auswahlmöglichkeiten. Überprüfen Sie zum Beispiel x86-64 unter Windows. Sie finden andere Größen als hier gezeigt.
Eerorika
@RobertSsupportsMonicaCellio Meiner Meinung nach sind diese Kommentare für die Antwort relevant und hier angemessen. Ich würde sie von einem Moderator bewegen lassen, wenn sie das Bedürfnis dazu haben.
Eerorika
11

Sie sind es nicht, zumindest nicht zuverlässig.

Die schnellen Typen sind einfach typedefs für reguläre Typen, es liegt jedoch an der Implementierung, wie sie definiert werden. Sie müssen mindestens die gewünschte Größe haben, können aber auch größer sein.

Es ist richtig, dass auf einigen Architekturen einige Ganzzahltypen eine bessere Leistung aufweisen als andere. Beispielsweise hatten frühe ARM- Implementierungen Speicherzugriffsanweisungen für 32-Bit-Wörter und für vorzeichenlose Bytes, aber sie hatten keine Anweisungen für Halbwörter oder vorzeichenbehaftete Bytes. Die Anweisungen für Halbwörter und vorzeichenbehaftete Bytes wurden später hinzugefügt, bieten jedoch immer noch weniger flexible Adressierungsoptionen, da sie in den freien Codierungsbereich eingefügt werden mussten. Darüber hinaus arbeiten alle tatsächlichen Datenverarbeitungsanweisungen in ARM mit Wörtern. In einigen Fällen kann es daher erforderlich sein, kleinere Werte nach der Berechnung auszublenden, um korrekte Ergebnisse zu erzielen.

Es gibt jedoch auch das konkurrierende Problem des Cache-Drucks, selbst wenn mehr Anweisungen zum Laden / Speichern / Verarbeiten eines kleineren Werts erforderlich sind. Der kleinere Wert kann immer noch eine bessere Leistung erzielen, wenn er die Anzahl der Cache-Fehler verringert.

Die Definitionen der Typen auf vielen gängigen Plattformen scheinen nicht durchdacht worden zu sein. Insbesondere moderne 64-Bit-Plattformen unterstützen 32-Bit-Ganzzahlen in der Regel gut, doch die "schnellen" Typen sind auf diesen Plattformen häufig unnötig 64-Bit.

Darüber hinaus werden C-Typen Teil des ABI der Plattform. Selbst wenn ein Plattformanbieter feststellt, dass er dumme Entscheidungen getroffen hat, ist es schwierig, diese dummen Entscheidungen später zu ändern.

Ignorieren Sie die "schnellen" Typen. Wenn Sie sich wirklich Gedanken über die Leistung von Ganzzahlen machen, vergleichen Sie Ihren Code mit allen verfügbaren Größen.

Plugwash
quelle
7

Die schnellen Typen sind nicht schneller als alle anderen Integer-Typen - sie sind tatsächlich identisch mit einem "normalen" Integer-Typ (sie sind nur ein Alias ​​für diesen Typ) - welcher Typ auch immer der schnellste ist, um einen Wert von zu halten mindestens so viele Bits.

Es ist nur plattformabhängig, für welchen Integer-Typ jeder schnelle Typ ein Alias ​​ist.

Chris Dodd
quelle