An Templates hatte ich dabei auch gedacht. Man kann ja die Anzahl der Koordinaten als Templateparameter mit angeben. Oder einfach nur den boolschen Wert. Besser als irgendwelche defines.
An Templates hatte ich dabei auch gedacht. Man kann ja die Anzahl der Koordinaten als Templateparameter mit angeben. Oder einfach nur den boolschen Wert. Besser als irgendwelche defines.
...also, das ist alles zur Compilezeit schon bekannt.
Ich wollte eigentlich erstmal gar keine Optimierungen machen, die Lesbarkeit kosten. Aber das if(dim3) rund um den Block mit den z-Koordinaten fand ich jetzt nicht so schlimm, und wenn es 1/3 der Vergleiche spart, kann mans ja mal machen.
Mit Naturgesetzen kann man nicht verhandeln. --Harald Lesch
Ein Atomkrieg würde die Menschheit auslöschen. Hätte aber auch Nachteile.
Der Vergleich ist egal, du hast aber ein viel größeres Problem: Die unnötigen Koordinaten muellen dir den Speicher zu. Wenn nicht gerade alles in den L1 Cache passt musst du für jede Berechnung die unnötigen z-Koordinaten mit laden, weil sie auf den selben Cache-lines stehen. Ob du sie dann noch verarbeitest ist so gut wie egal.
Die eigentliche Herausforderung ist also das Speicherlayout entsprechend der Version anzupassen. Da gibt es verschiedene Ansätze: je nachdem was du mit den Koordinaten so anstellst wäre es sinnvoll eine Abstraktion zu gestalten über die sich 2D und 3D Koordinaten gleich bearbeiten lassen. Wenn die Wahl im Programm global ist kann auch ein -DCoordinate=Coordinate2D viel Code sparen. Man kann auch für die 2D Koordinaten leere constexpr getter und setter implementieren und sie so als 3D Koordinaten behandeln.
Achtung Spoiler:
Wieso? Es geht ja gerade darum eine gemeinsame Abstraktionsschicht fuer 2D und 3D Koordinaten zu nutzen, so dass 9x% des codes unabhaengig davon ist ob die 2D oder 3D Variante aktiv ist.
P.S.: -DCoordinate ist natuerlich nicht optimal schoen. Besser ist ein "normales" defineflag mit #if / typedef. Es gibt einige nette Tricks virtual functions zu optimieren, aber spontan faellt mir nnichts besseres mit 0-Overhead ein.
Fuer Interessierte/Fortgeschrittene kann ich waermstens die Talks der GoingNative 2013 empfehlen. Insbesondere die von Andrei Alexandrescu, Chandler Carruth, Stephan T. Lavavej und natuerlich Stroustrup , Scott Meyers.
Achtung Spoiler:
Damit sind wir trotz der Bedenken also doch bei einem Makro-Ansatz
Die Frage nach einer geeigneten Lösung hängt meiner Meinung nach stark von der vorhandenen Datenstruktur des restlichen Projektes ab. Aber ich denke wir sind uns alle einig dass die schnellen Lösungen alle separaten Code für den 2D und 3D ausführen sollten. Die Frage ist nur wie man möglichst wenig Redundanz erzeugt.
Bei freier Wahl würde ich auch zu etwas in der Art
tendieren und nicht unbedingt Templates nur für diese eine Sache einführen.Code:#ifdef DIM3D typedef Point3D Point #else typedef Point2D Point #endif
Nachteil an der Sache ist, dass man dann wirklich nur 2D oder 3D nutzen kann. Oft will man später dann aber für irgendwelche Unteraufgaben auch bei 3D auf niedrige Dimensionen zurück greifen.
P.S. In der Theorie wird oft geschrieben, dass man den 3D-Fall analog zum 2D-Fall lösen kann. Häufig ist das in der Praxis aber nicht so Da wird dann erst versucht den 2D-Code für 3D lauffähig zu gestalten, was tausend Probleme verursacht und am Ende wird doch für 3D neu programmiert. Gewisse geometrische Eigenschaften sind in 3D einfach anders...
Also gelernter Mathematiker empfehle ich, für den allgemeinen Fall n > 0 zu programmieren und dann die Spezialfälle n=2 und n=3 zu betrachten
Hat irgendjemand einen Plan wie ich meine blöde Python IDLE dazu bringe, die Pakete aus WinPython oder Anakonda zu benutzen?
Nachteil hier ist, dass man diese Art der Fallunterscheidung im gesamten Programm durchziehen muss.
Besser ist es auch, die Koordinaten in einen Array zu speichern. Die Boost-Bibliotheken haben eine Template-Array Klasse, die im Prinzip ein Wrapper für die rohen Arrays sind, sich aber weitgehend wie die Standardcontainer verhalten. (In C++ 11 ist sie schon im Standard enthalten.)
Man kann die Länge des Arrays als Templateparameter übergeben. Und dann entsprechende Templatefunktionen schreiben.
Die Norm könnte man dann etwa so grob schreiben:
Diese Funktion kann man sowohl in 2D als auch 3D verwenden, und man muss sie nur einmal schreiben.Code:template<size_t N> double norm(const array<double, N>& xs) { double x = 0; for (size_t i = 0; i < N; ++i) {x += xs[i] * xs[i];} return std::sqrt(x); }
Ein solche verwendung von Makros ist trotzdem wesentlich besser als der intiale Ansatz. Hier ist der Makro-Code absolut konzentriert und bietet damit wesentlich weniger Angriffsflaeche fuer die Probleme von Makros.
ACs vorschlag mit std:array ist auch sehr gut - vorausgesetzt die Dimensionen sind gleichartig.
Achtung Spoiler:
Kann mir jemand erklären warum das hier net klappt:
double x = std::stod("0.0");
$>g++ -o p.exe main.cpp -std=c++11
main.cpp: In function 'void initPersVec(std::vector<Person>&)':
main.cpp:52:16: error: 'stod' is not a member of 'std'
double x = std::stod("0.0")
#include <string> ist auch dabei.
http://www.cplusplus.com/reference/string/stod/?kw=stod
Der Standard wird noch nicht unterstützt werden, nimm
g++ -std=c++0x -o p.exe main.cpp
Welche Kompiler-Version hast du? MinGW G++ sollte ab Version 4.8.2 das unterstützen.