C++ 8 bit integer

Gandalf2210

Commodore
Registriert
Mai 2010
Beiträge
4.137
Hallo zusammen
Ich möchte eine simulation für ein Spiel machen.
Da die je nach parameter ziemlich umfangreich ausfallen kann, wollte ich direkt zu anfang auf performance achten und würde gerne einen 8 bit integer nutzen.
gibt es so etwas in c++? (Visual Studio Windows 8 x64)
Ich könnte einen unsigned char nehmen, allerdings kann ich den nicht direkt ausgeben, sondern muss ihn auf int casten, damit da wieder ne Zahl draus wird. Kostet der cast Zeit zur Laufzeit, oder kann der während des kompilieren schon sagen, dass der wie in int zu behandeln ist?
kann ich denn mit dem char sonst so rumrechen und vergleiche wie mit einen ganz normalen int?

mfg Gandalf2210
 
Ganz ehrlich: Bau erstmal alles zusammen. An der Performanceschraube kannst du immer noch drehen. Wenn du jetzt wegen dem Performancewahn schon viele Fallstricke einbaust, hast du im Endeffekt viel mehr Arbeit und Bugs, als wenn du es zuerst ordentlich gemacht hättest. Gewartet und erweitert werden will der Code ja schließlich auch noch. Performanceoptimierter Code ist da der letzte Husten...
 
Übrigens: 8-bit-Integer sparen dir wohl Speicher, aber wenn es dir nicht darauf, sondern auf Geschwindigkeit ankommt, dann schaden sie dir eher. Am schnellsten (sofern sich der Unterschied überhaupt bemerkbar macht) sind Datentypen, deren Größe deiner Architektur entspricht, also 64-bit-Integer auf 64-bit-Maschinen usw.
 
Wenn Du einen 8 Bit Integer verwendest, bist Du sowohl vom Assembler-Code her größer als auch von der Laufzeit her langsamer, da der 8 Bit Integer nicht direkt aus dem Speicher gelesen werden kann, sondern erst durch eine Cast-Operation aus einem 32- oder 64-Bit-Wert erzeugt wird.
 
@NullPointer
hmm, der speicherverbrauch ist kein thema, das sind nur ein paar kb, die gebraucht werden. Ich hatte eher sorge, dass bei großen ints die Schreibleistung vom RAM, cache... limitiert, da die rechenoperationen immer nur +1 sind

@Lunke
danke, werde ich damit mal probieren

@Turner123
der speichert also einen normal großen 32 bit integer und verkleinert den dann erst "künstlich" per typecast?
 
Schließe mich meinem Vorredner an, vergiss mal anfangs die Performance. Das führt nur schnurgerade in Teufels Küche und kostet dich mehr Zeit als du dir vorstellen kannst.

Zum technischen: bei integral promotions wird ein char automatisch in ein int konvertiert wenn es zu arithmetischen Operationen kommt. Auch ansonsten wird auf den größeren Typ konvertiert, z.b. wird bei short und int das short in ein int konvertiert. D.h. du musst das nicht händisch casten, da es sowieso automatisch geschieht. Damit kannst du in deinem Code ganz am Beginn ein einfaches typedef wie:

Code:
typedef int my_small_int; // or whatever type / name

machen und dann in deinem Code ganz 'normal' nutzen -> arithmetische Operationen finden 'normal' statt, und du kannst den zugrunde liegenden Datentyp bei Bedarf einfach in einer einzigen Zeile austauschen. Du kannst dir ja selbst eigene Annahmen setzen welche Werte dieser Typ max. annehmen darf um überall im Code korrekt zu funktionieren (z.b. ohne overflow).

Übrigens: ein ganz banales int wird weder bzgl. Peformance noch bzgl. Datenrange eine schlechte Default-wahl sein ...
 
Das hängt vom jeweiligen Compiler ab. Entweder wie Du sagst oder alternativ vier 8Bit-Werte auf einer 32Bit-Adresse (oder 16 Werte bei 64 Bit). In beiden Fällen wird vom Compiler folgender folgender Code erzeugt:
1. Lese 32Bit-Wert
2. Und-Verknüpfung mit 0x000000ff (bzw. 0x0000ff00, 0x00ff0000, 0xff000000 für den zweiten Fall) durchführen

Wenn Du genug Ram hast, verwende als Datentyp Integer. Das ist der schnellste Zugriff.
 
Wie die anderen schon angemerkt haben ist das keine gute Idee, nichts desto trotz:

Code:
#include <cstdint>

typedef std::uint8_t my_small_int;
 
Außerdem:
Code:
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char c = 42;
    printf("%c = %u\n", c, c);
    return EXIT_SUCCESS;
}

// Ausgabe:
// * = 42
 
Unter Windows gibts den BYTE datentyp welcher einem unsigned char entspricht. __int8 ist die explizite deklaration.

Typecast verbraucht keinerlei zusätzliche zeit.

Falls mehrer byte variablen verwendet werden, kann der code durchaus schneller sein, im schlechtesten falle gleich schnell. Gerade eben wegen dem speicher lesen/schreiben. Der compiler kann viel besser optimieren wenn du sagst du brauchst nicht das komplette register. Weniger speicherzugriffe und mehr verlagerung in register sind die Folge.
Die ror rol assembleroperationen existieren nicht ohne grund.

Auch wird dein generierter code eventuell minimal kleiner. Aber bei cpp juckt das sowieso nicht.

Achte v.a. auf Funktionalität und Effektivität von Algorithmen, wenn du nen fehler wegen nem overflow reinbringst dauerts ewig den zu finden.
 
im schlechtesten falle gleich schnell.
Im schlechtesten Falle eher langsamer, weil 8/16-Bit-Operationen immer partielle Registerabhängigkeiten haben, beim Lesen aus dem Cache auf den meisten CPUs für Cache Bank Conflicts sorgen und beim Schreiben aus demselben Grund eine absolute Katastrophe sind, sofern dicht gepackte Werte tatsächlich gleichzeitig verwendet werden. Problem Nummer 1 ist dabei in der Regel das geringere Übel und lässt sich schon mit 32bit-Integern lösen, Problem Nummer 2 je nach Anwendung und CPU entweder durch 64bit-Integer oder durch "intelligentes" Laden/Speichern der Werte, sodass man nicht 2x nacheinander auf dieselbe Cache-Bank zugreift.

Speicher bei so simplen Sachen sparen macht erst dann wirklich Sinn, wenn die Daten nicht mehr in den L2- oder, wenn nur kurz gerechnet wird, dafür aber mit allen Werten auf einmal - in den L1-Cache passen.
 
Diese pauschale Ablehnung von 8 Bit Werten kann ich nicht nachvollziehen. Bei SSE/AVX Registern passen einfach mehr Werte rein, wenn man 8 Bit Werte nimmt. AVX Register sind immerhin 256 Bit Breit, macht bei 8 Bit Werten 32 Werte gleichzeitig, bei 32 Bit Integers nur 8. (ja, man kann wirklich 32 8Bit Werte gleichzeitig mit einer Instruktion verarbeiten. Für's Addieren lautet die Instrinsic Funktion bspw. _mm256_add_epi8, einfach mal im Intel Intrinsics Guide nachschauen). Da ginge Performanceverlust mit der Speichersplatzverschwendung 1:1 einher. Ob 8 Bit Werte irgendeine Form von Performance Problemen verursacht, werde ich bei Gelegenheit noch prüfen. Ich hätte nämlich erstmal da keine Einschränkungen erwartet. Alles was kleiner 8 Bit ist, ist in der Tat unsinning, weil man für einzelnen Bits dann tatsächlich Shift Operationen anwenden muss. Ist das nur Spekulation oder Wissen, ob 8 Bit mit Performance Nachteilen verbunden ist? Sonst schenk ich mir das recherchieren, weil ich das für hochgradig unwahrscheinlich halte. Ein Buchstabe ist meisten weiterhin 8 Bit groß und Graustufenbilder sowieso. Wäre mir neu wenn irgendwer auf die Idee käme ein Graustufenbild auf ein 32/64 Bit Farbtiefe aufzublasen, der Performance wegen.
 
Die Frage nach Performance - Vorteile wie Nachteile - lässt sich doch ohne zugrundeliegendem Kontext (code / Programmexekution / Compiler / Exekutionsumgebung) sowieso nicht vollständig beantworten. Theoretisch wirds das Programm wohl schneller wie auch langsamer machen können. Und ob der Compiler AVX Register (inkl. möglichen vectorized instructions) richtig ausnutzen vermag sei auch mal dahingestellt.

Die entscheidende Frage ist doch eigentlich obs auch einen spürbaren (und nicht nur rein theoretischen oder gerade mal messbaren) Einfluss auf die Performance gibt. Mein Bauchgefühl sagt mir aber, dass bei einem 'normalen' Programm die Unterschiede wohl marginal sind, also kein spürbarer Einfluss. Die Risiken, sich mit zu kleinen Datentypen aber overflows oder andere Probleme einzufangen, oder von Haus aus auf irgendwelche Optimierungen fixiert sein aber dabei das Programm als ganzes aus den Augen zu verlieren, sind IMHO bedeutend größer in der Praxis.
Nur der OP kann die Performance-Frage in seinem Fall beantworten. Das hingegen aber leicht wenn das Programm von Haus aus einfach generisch bzgl. dieses Datentyps ausgelegt wird und eben einen Wechsel einfach macht (Stichwörter type-generic programming / templates, typedefs etc.)
 
Gerade bei Simulationen, die groß werden können, sollte man für Werte, die sicher in 8 Bit passen, auch nichts größeres verwenden. Die je nach CPU ggf. auftretenden Verzögerungen bei unaligned Zugriffen sind nichts verglichen mit den Folgen durchs sinnlose Aufblasen der Datenmenge um Faktor 4 oder 8.
 
Zurück
Oben