[C++] Gleitkomma- zu Ganzzahlen runden

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Benutzeravatar
Schrompf
Moderator
Beiträge: 5401
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Schrompf »

Wow, will haben! Pack's in eine kleine Funktion und mach einen dicken Kommentar drumrum, dass das im Falle einer Portierung geändert werden muss, dann hast Du nach meiner Meinung ausreichend Portabilität erreicht :-) Man sollte sich bei all diesen Überlegungen halt auch mal vor Auge halten, wer denn am Ende den Source wirklich mal in die Hand bekommt und auf welchen Compilern/Systemen der dann übersetzt werden soll. Wenn man da ehrlich zu sich selbst ist, ist bei 90% der Leute die Antwort: ein Rechner. Nämlich der eigene. Von daher: Portabilität wird allgemein überbewertet.

In Deinem Fall ist die Sache wohl kniffliger, weil Du tatsächlich selbst die 64Bit-Variante brauchst. In dem Fall musst Du wirklich weitersuchen. Ich würde mich dagegen freuen, wenn Du einfach mal Deinen bisherigen 32Bit-Inline-ASM-Code posten könntest... zu ähh... Lernzwecken :-)

Bye, Thomas
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
kimmi
Moderator
Beiträge: 1416
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von kimmi »

Zum Thema Portabilität: bei privaten Projekten stimme ich Schrompf voll zu.
Bei beruflich motivierten Projekten: Ich habe schon unzähliche Überstunden geschoben, weil jemand Portabilität auf die zu leichte Schulter genommen hat und ein Compilerwechsel von x.00x auf x.00x+1 unerklärbare Abstürze provozierte :) . Also bitte beruflich zumindest mehr als einmal drüber nachdenken, danke ;) . Eure Nachfolger werden es euch danken.
Und ja, ich weiß, gehörte nicht zum Thema.

Gruß Kimmi
Benutzeravatar
Schrompf
Moderator
Beiträge: 5401
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Schrompf »

Öhm... ich rede von Compile-Time-Fehlern, die die zu portierenden Funktionen auf einem anderen System werfen sollten. Fehler zur Laufzeit sind unbedingt zu vermeiden. Im einfachsten Fall packt man einfach ein Boost-StaticAssert in die entsprechende Funktion, um Compiler und Prozessorarchitektor zu verifizieren, für die der Inline-ASM gedacht ist.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
kimmi
Moderator
Beiträge: 1416
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von kimmi »

Und ich rede von Laufzeitfehlern, die aufgrund einer schlecht portierten Funktion / Methode entstanden sind, da jemand leider keine StaticAsserts um besagte Stelle gebaut hat. Gerade beim Erben von Legacy-Code habe ich derartige Probleme schon oft miterleben dürfen ( bei Compilerwechsel, Systemwechsel, OS-Wechsel, auch gern mal Wetterwechsel ;) ). Nicht jeder geht da so bewußt ran wie Schrompf :(.

Gruß Kimmi
Benutzeravatar
Krishty
Establishment
Beiträge: 8422
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Krishty »

Schrompf hat geschrieben:Ich würde mich dagegen freuen, wenn Du einfach mal Deinen bisherigen 32Bit-Inline-ASM-Code posten könntest... zu ähh... Lernzwecken :-)
Gern, hier ist er. Ich habe einfach mal Referenzen statt einem Rückgabewert benutzt, weil das für die Benchmarks wahrscheinlich vorteilhaft ist:

Code: Alles auswählen

inline void RoundSingle(const float & p_Source, signed int & p_Dest) {
	__asm fld p_Source
	__asm mov edx, p_Dest
	__asm FRNDINT
	__asm fistp dword ptr [edx];
}
Und was zum Lernen dazu: Die FPU arbeitet standardmäßig im Modus "round" (weil die Rechenergebnisse dann am nächsten an den mathematisch richtigen Ergebnissen liegen). Führt man einen static_cast<signed int>() durch, wird ftoi() aufgerufen. Diese speichert den aktuellen FPU-Modus, flusht alle Anweisungen, setzt den Modus auf "chop" (Abschneiden der Nachkommastellen), konvertiert die float zur signed int, stellt den zuvor gespeicherten Modus wieder her und fährt dann fort ... darum ist er so langsam, eine komplette Verschwendung wenn man eh runden möchte.
The Code Project bietet einen guten Artikel mit Haufen von nützlichen Float-Utilities, dort habe ich auch die Funktion her (die gibt es aber im Netz an jeder Ecke).
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
kimmi
Moderator
Beiträge: 1416
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von kimmi »

Da sag ich ebenfalls Danke! Und der Link beinhaltet einiges sehr interessantes Zeug.

Gruß Kimmi
Benutzeravatar
Krishty
Establishment
Beiträge: 8422
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Krishty »

Ähm, eine Frage am Rande … ich habe ja nicht viel Assembler-Erfahrung …

Ich habe die Funktion jetzt so umgebaut, dass sie einen Rückgabewert hat (signed int RoundSingle(float p_Value)). Da die Funktion keine lokalen Variablen benötigt und keine großen Parameter handhabt, habe ich sie __declspec(naked) gemacht und die Aufrufmethode __fastcall gewählt.

Darum meine Frage an die Experten: Ist das akzeptabler Stil? Werden „nackte“ Funktionen auch von anderen Compilern als VCpp unterstützt? Habe ich irgendwelche Probleme zu erwarten?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
kimmi
Moderator
Beiträge: 1416
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von kimmi »

Wenn ich die Postings von der gcc-ML richtig verstanden habe, unterstützen die ein __attribute__((naked)) , welches aber nicht auf allen Plattformen unterstützt wird: http://www.mailinglistarchive.com/gcc-h ... 08166.html
Müsste man mal probieren bzw. auf jemanden warten, der das genauer weiß als ich :-).

Gruß Kimmi
Benutzeravatar
Krishty
Establishment
Beiträge: 8422
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Krishty »

Stimmt, auf x86 bspw. ist es ungültig und wird es wohl auch immer bleiben. Ich sehe aber gerade, dass ich scheinbar kein naked mehr angeben muss, wenn ich die Funktion in einer externen Datei assembliere – was ich der x64-Kompatibilität wegen ja sowieso machen muss.

Momentan habe ich aber noch Probleme mit MASM, ich melde mich zurück, wenn es funktioniert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Jörg »

Wozu frndint in der Funktion? fistp allein rundet auch....
Benutzeravatar
Krishty
Establishment
Beiträge: 8422
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Krishty »

seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Jörg »

Oh, das wuerde mich sehr erstaunen, in welchen Faellen unterscheidet sich fistp von frndint im Rundungsverhalten?
Benutzeravatar
Krishty
Establishment
Beiträge: 8422
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Krishty »

Laut dem Artikel käme bei 65535.5 das Ergebnis 0 statt 65536 raus, wenn man frndint nicht explizit voran stellte.
Das ist ein Bug im Pentium-Prozessor, genau wie diese leidige fdiv-Sache damals … eigentlich ewig her und man könnte es weglassen … nur weiß man ja nie, worauf ihr den Code ausführt.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Jörg »

Wenn ich das richtig lese, kannst du das ignorieren, da du fuer das Auftreten eh den Wertebereich der Ziels ueberschreiten musst.
http://support.microsoft.com/kb/126455/en-us
Benutzeravatar
Krishty
Establishment
Beiträge: 8422
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Krishty »

Stimmt :)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8422
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Krishty »

So, kleines Update … ohne frndint hat sich die Performance nochmal fast verdoppelt, ich bin jetzt bei der 45-fachen Geschwindigkeit eines static_cast – danke, Jörg.

Mit dem Assembler-Code, der nun endlich nicht mehr inline-Assembler ist, sondern mit MASM assembliert und extern gelinkt wird, ist allerdings der GAU eingetreten: Er wird nicht geinlined. Die Performance ist damit um den Faktor 100 schlechter geworden und ist nun nurnoch halb so schnell wie ein static_cast.

Hat jemand ein gutes Tutorial darüber, wie man MASM-Kompilate richtig in Visual-C++-Projekte einbindet und optimiert? Ich habe mich da quasi blind reingetastet und ihr seht, was rauskommt …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8422
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Krishty »

Ich habe keinen Bock mehr … ich werde erstmal die SSE-Intrinsics nutzen … sind genauso schnell wie fistp aber x86- sowie x64-tauglich … CPUs ohne SSE sind eh zu langsam für meine Bedürfnisse und den winzigen Präzisionsunterschied gegenüber der FPU würde ich ja eh nicht messen können … Assembler ist nervtötend und wenn ich noch mehr Zeit auf das Thema verschwende, kriege ich garnichts mehr gebacken -.-

Daher meine vorläufige Lösung, falls ihr nichts daran auszusetzen habt:

Code: Alles auswählen

#include <intrin.h>

signed int RoundFloatToInt(const float & p_Value) {
	return ::_mm_cvt_ss2si(::_mm_load_ss(&p_Value));
}

signed int TruncFloatToInt(const float & p_Value) {
	return ::_mm_cvtt_ss2si(::_mm_load_ss(&p_Value));
}

signed int RoundDoubleToInt(const double & p_Value) {
	return ::_mm_cvtsd_si32(::_mm_load_sd(&p_Value));
}

signed int TruncDoubleToInt(const double & p_Value) {
	return ::_mm_cvttsd_si32(::_mm_load_sd(&p_Value));
}
Ich danke euch für eure Hilfe, in dem Thread ist ja letztendlich doch ein Haufen von Wissen und interessanter Codefragmente über FPU, Bitshifterei mit Gleitkommazahlen und Assemblertrickserei zusammengekommen :)

Falls Interesse daran besteht, wie man komplette Assembler-Dateien zu Visual-C++-Projekten linkt, kann ich noch ein Tutorial drüber schreiben – jetzt weiß ich ja, wie es geht.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8422
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Gleitkomma- zu Ganzzahlen runden

Beitrag von Krishty »

Dieser Sache scheint man niemals Herr werden zu können -.-

Ich brauche jetzt eine zur 64-Bit-Integer gerundete Gleitkommazahl (die SSE-Intrinsics sind also nicht mehr ausreichend), ich brauche sie unter x64 (also goodbye, Assembler) und ich brauche sie performant.

Ich habe im Verlauf des Threads ja schon festgestellt, dass es dafür keinen portablen Code zu geben scheint – falls hier aber doch nochmal jemand drüber stolpert (oder auch nur über ein halb-portables Intrinsic), sei er ausdrücklich darum gebeten, zu antworten …

Wahnwitz und Idiotie, dass es für jeden Müll Intrinsics und Optimierungen gibt, man aber gerade bei sowas auf einem 24× langsameren, kaum praktisch anwendbaren Umweg beharrt.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten