Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!
Werbeanzeige
![]() |
C-/C++-Quelltext |
1 2 3 4 5 6 7 8 9 10 11 12 |
static const float epsilon = 0.00001; static const double epsilon64 = 0.00000001; template <typename T> T Epsilon() { return T(epsilon); // By default 32-bit epsilon } template <> double Epsilon<double>() { return epsilon64; // Specialized template } |
Zitat von »LukasBanana«
Der Grund dafür ist, dass Templates den Code extrem aufblähen - aber ist das heutzutage noch tragisch?
Zitat von »Krishty«
Für double ändern sich normalerweise auch alle Toleranzen und Epsilons in deinem Quelltext; die lassen sich nur sehr schwer template-isieren.
Zitat von »Krishty«
zum anderen ergibt zwar float * float wieder float, aber für int * int möchtest du in den meisten Fällen unsigned int oder unsigned long.
Zitat von »Krishty«
nicht mehr einen Skalartypen als Parameter, sondern drei, weil je nach Rechenweg jede Komponente unterschiedlich hohe Genauigkeit hat.
Zitat von »Krishty«
Premature reuse is the root of all evil.
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Spiele Programmierer« (15.04.2014, 13:31)
Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer
Nein, eben nicht. Das Wort "premature" schließt die Entscheidung des Einzelfalls schon ein.Das ist genauso eine Wirtshausparole wie die bekannte "Premature Optimzation".
Man muss im Einzellfall entscheiden.
int bietet konstante Genauigkeit und erlaubt in gewissem Rahmen stabilere Berechnung (a + b entspricht bei int dem genauen Ergebnis, wird mit float aber unter Umständen gerundet; int-Funktionen greifen wie Zahnräder ineinander während float-Funktionen sich immer überlappen oder Lücken bilden). Diese Vorteile sind bei Positionen in großen Welten sehr deutlich. Bei Geschwindigkeiten hingegen sind Gleitkommazahlen erste Wahl weil sie höhere Dynamik erlauben; bei 3D-Grafik auch (weil das, was weit weg vom Betrachter ist, auch nicht so genau sein muss wie das nah dran).Warum sollte man denn "int" als Datentyp für Kollisions-Funktionen nehmen?
Ich dachte jetzt eigentlich nur an "float" und "double".
Naja … such mal das CAD-Programm deiner Wahl raus und interpretier den Datenabschnitt als double; dann wird dir wahrscheinlich schlecht
Zitat von »Krishty«
Für double ändern sich normalerweise auch alle Toleranzen und Epsilons in deinem Quelltext; die lassen sich nur sehr schwer template-isieren.
Verstehe ich nicht ganz. Erstens glaube ich nicht, dass man sehr viele Epsilons brauchen sollte und zweitens gibts es ja "std::numeric_limits" mit dem die wichtigsten Werte generisch herauszufinden sind. Des Weiteren sollte man solche Werte ohnehin nicht einfach als magische Zahlen in den Code schreiben, sondern dafür Konstanten verwenden. Diese Konstanten könnte man auch ganz einfach in eine spezialisierte Templateklasse packen um je nach Datentyp andere Werte zu verwenden. Ich sehe darin keinen Grund auf Templates zu verzichten.
Bei Schnittpunktberechnungen mit Strecken berechnet man z.B. oft den Schnitt einer Linie und prüft dann, ob die Projektion auf die Strecke zwischen 0 und 1 liegt. Das möchte man bei Festkommazahlen nicht weil die Division destruktiv ist. Der Rechenweg lässt sich stattdessen z.B. ändern, so dass mit 0 < n² < Länge² verglichen wird. Sowas kann ein Template nicht.
Zitat von »Krishty«
zum anderen ergibt zwar float * float wieder float, aber für int * int möchtest du in den meisten Fällen unsigned int oder unsigned long.
Welche Berechnungsvorschriften sollen sich ändern?
… oder bei Überladung bleiben, die sehr viel einfacheren Regeln folgt.In Ausnahmefällen kann man spezialisieren.
Falls du mit Festkommazahlen arbeitest, willst du aber wissen, wo das Komma ist. Das kann man im Template-Parameter festhalten, und kann sich eben auch für alle Komponenten unterscheiden. Damit sind es für deinen Compiler auch verschiedene Typen.
Zitat von »Krishty«
nicht mehr einen Skalartypen als Parameter, sondern drei, weil je nach Rechenweg jede Komponente unterschiedlich hohe Genauigkeit hat.
Das wäre in der Tat ziemlicher Quatsch. Am Besten nimmt man einfach "std::int64_t" für alles. Damit kann man eigentlich so gut wie jeden Wert abdecken und in der Zeit der 64Bit CPUs ist auch der Rechenaufwand kein großes Problem mehr. Da unterschiedliche Typen zu verwenden, würde nur alles viel komplizierter machen als es ist.
Er soll entscheiden, ja. Wenn er eine double-Variante oder eine Festkommavariante benötigt, soll er die schreiben und testen. Und wenn sie funktioniert und dann *immernoch* den gleichen Quelltext hat wie die float-Variante, *dann* soll er sich entscheiden.Das kann aber nur LukasBanana selbst entscheiden.
Zitat von »BlueCobold«
Nein, eben nicht. Das Wort "premature" schließt die Entscheidung des Einzelfalls schon ein.
Zitat von »Krishty«
nur in der 3D-Vektor-Normalisierung gebraucht wird, macht man keine globale Template-Konstante draus.
Zitat von »Krishty«
Das kann man im Template-Parameter festhalten, und kann sich eben auch für alle Komponenten unterscheiden.
Zitat von »Krishty«
*dann* soll er sich entscheiden.
Das kann durchaus sinnvoll sein um hier und da noch ein Bisschen Genauigkeit rauszuholen – ich weiß bei meinem Flugsimulator, dass man sich zwar 4000 km nach X oder Z bewegen kann, aber nur 100 km nach Y. Aber mir wird gerade klar, dass ich durch die Bank „Festkomma“ mit „statisch vorberechnetes gleitendes Komma“ durcheinanderschmeiße. Bei Festkommazahlen hat man tatsächlich nur einen Typ für alles; dafür aber kaum mehr Vorteile gegenüber Gleitkommazahlen.
Zitat von »Krishty«
Das kann man im Template-Parameter festhalten, und kann sich eben auch für alle Komponenten unterscheiden.
Es macht kaum Sinn in einem Vektor verschiedene Zahlen mit verschiedenen mit verschiedenen Kommas zu speichern. Ein Vektor besteht aus mehreren Koordinaten des selben Types. Nicht X als "float", Y als Festkomma "32.32" und Z als Ganzzahl. Ein Vektor hat für alle Komponenten den selben Wertebereich.
Zitat von »Krishty«
*dann* soll er sich entscheiden.
Dann darf er erstmal den gesamten Code und insbesondere die Abhänigkeiten umschreiben.
Das hatte ich so interpretiert dass der Quelltext bereits geschrieben ist. Jetzt wo du es erwähnst bin ich mir aber auch nicht mehr sicher.Immer hin sind diese Templates nicht gerade klein und ich habe eine ganze Menge davon (Intersection Test mit Line/Ray mit AABB/Sphere/Capsule etc., Distanz Berechnungen zwischen Point/Line gegen AABB/Sphere/Triangle etc.).
Ja, aber niemand hat eine Kristallkugel. Meiner Meinung nach sollte man den einfachsten möglichen Weg zuerst implementieren und erweitern, sobald man an die Grenzen kommt. Das bedeutet zwar häufiges Umschreiben, aber dafür bleibt die Funktionsweise einfach. Quelltext, der für Großes ausgelegt ist, ist normalerweise viel schwerer fehlerfrei zu kriegen.Soetwas sollte man sich in der Regel vorher überlegen, sonst hat man nachher mehr Arbeit als notwendig gewesen wäre.
Zitat von »Krishty«
Das kann durchaus sinnvoll sein um hier und da noch ein Bisschen Genauigkeit rauszuholen
Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer
Ich glaube da unterliegst Du einem Irrtum. Wenn Du Abstände zwischen Mond und Erde korrekt modellierst, wirst Du feststellen, dass sich Nanometer eben nicht mehr bestimmen lassen. Sogar mit Zentimetern wird es dann schon problematisch. Double kann zwar große Wertebereiche abdecken, aber die Genauigkeit ist relativ zum absoluten Wert des Doubles. Große Zahlen führen dazu, dass Nachkommastellen oder sogar die unteren Stellen vor dem Komma nicht mehr dargestellt werden können. Bei Double sind das in etwa 15 Stellen. Da wird bei den 18.446.744km nix mehr die Nanometer aufzulösen, die stolze 20 Stellen bräuchten.Mit 64Bit Werten wie ich sie heute verwenden würde, kaum noch. Bei einer Genauigkeit von einem Nanometer, würde der Wertebereich für bis zu 18 446 744km Abstand reichen. Das reicht locker, als das von der Erde aus, auch noch der Mond mit in den Wertebereich passt.
Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »BlueCobold« (16.04.2014, 07:21)
Werbeanzeige