Ich habe einen Algorithmus, wo ich (viel Zeit) doppelte Zahlen in der E-40 bis e + 40 summieren müssen.summieren Array von Doppel mit großem Wert span: richtigen Algorithmus
Array Beispiel (zufällig aus realen Anwendung dumped):
-2.06991e-05
7.58132e-06
-3.91367e-06
7.38921e-07
-5.33143e-09
-4.13195e-11
4.01724e-14
6.03221e-17
-4.4202e-20
6.58873
-1.22257
-0.0606178
0.00036508
2.67599e-07
0
-627.061
-59.048
5.92985
0.0885884
0.000276455
-2.02579e-07
Es versteht sich von selbst, die ich bin mir bewusst, der Effekt Rundung wird dies dazu führen, ich versuche, es unter Kontrolle zu halten: das Endergebnis sollte keine fehlenden Informationen im Bruchteil des doppelten oder, wenn nicht vermeidbaren Ergebnisses sollten mindestens n-stellig genau sein (mit n definiert). Das Endergebnis benötigt etwa 5 Ziffern plus Exponent.
Nach einem paar anständigen Denken, landete ich mit folgendem Algorithmus auf:
- sortiert das Array, so dass der größte Absolutwert an erster Stelle steht, die am nächsten zu Null reicht.
- alles in einer Schleife
Die Idee ist, in diesem Fall hinzufügen, dass jede Stornierung von großen Werten (Negative und positive) wird letztere kleinere Werte nicht beeinflussen. Kurz In:
- (10e40 - 10e40) + 1 = 1: Ergebnis wie erwartet
- (1 + 10e40) - 10e40 = 0: nicht gut
Ich landete mit std :: multiset (Benchmark auf meinem PC gab 20% höhere Geschwindigkeit mit langen Doppel im Vergleich zu normalen Doppel - ich bin in Ordnung Doppelauflösung) mit einer benutzerdefinierten Sortierfunktion mit Std: Fabs.
Es ist immer noch ziemlich langsam (es dauert 5 Sekunden, um das Ganze zu tun) und ich habe immer noch das Gefühl von "Sie haben etwas in Ihrem Algo verpasst". Jede Empfehlung:
- für die Geschwindigkeitsoptimierung. Gibt es eine bessere Möglichkeit, die Zwischenprodukte zu sortieren? Das Sortieren einer Menge von 40 Zwischenergebnissen (typischerweise) dauert etwa 70% der gesamten Ausführungszeit.
- für verpasste Probleme. Gibt es eine Chance, weiterhin kritische Daten zu verlieren (eine, die im Bruchteil des Endergebnisses liegen sollte)? (Z (jw) elektrische Impedanz)
auf ein größeres Bild, ich Polynom Klassen von rein imaginären variablen reellen Koeffizienten bin der Umsetzung. Z ist ein großes Polynom, das ein benutzerdefiniertes System darstellt, wobei der Koeffizientenexponent sehr weit reicht.
Das "große" kommt von Hinzufügen von Sachen wie Zc1 = 1/jC1w zu Zc2 = 1/jC2w:
Zc1 + Zc2 = (C1C2 (jw)^2 + 0 (jw))/(C1 + C2) (jw)
In diesem Fall, mit C1 und C2 in Nanofarad (10e-9), ist C1C2 bereits in 10e-18 (und es begann nur ...
)meine Sortierfunktion eine Manhattan-Distanz von komplexen Variablen verwenden (weil, Minen entweder rein reell oder rein imaginär) sind:
struct manhattan_complex_distance
{
bool operator() (std::complex<long double> a, std::complex<long double> b)
{
return std::fabs(std::real(a) + std::imag(a)) > std::fabs(std::real(b) + std::imag(b));
}
};
und meinen Multi Satz in Aktion:
std:complex<long double> get_value(std::vector<std::complex<long double>>& frequency_vector)
{
//frequency_vector is precalculated once for all to have at index n the value (jw)^n.
std::multiset<std::complex<long double>, manhattan_distance> temp_list;
for (int i=0; i<m_coeficients.size(); ++i)
{
// element of : ℝ * ℂ
temp_list.insert(m_coeficients[i] * frequency_vector[i]);
}
std::complex<long double> ret=0;
for (auto i:temp_list)
{
// it is VERY important to start adding the big values before adding the small ones.
// in informatics, 10^60 - 10^60 + 1 = 1; while 1 + 10^60 - 10^60 = 0. Of course you'd expected to get 1, not 0.
ret += i;
}
return ret;
}
The Projekt, das ich habe, ist C++ 11 aktiviert (hauptsächlich für die Verbesserung der Mathematik lib und komplexe Anzahl Werkzeuge)
PS: Ich refaktoriert den Code zu machen ist einfach zu lesen, in Wirklichkeit alle Komplexe und lange Doppelnamen sind Vorlage: Ich kann das Polynom Art in kürzester Zeit ändern oder die Klasse für reguläres Polynom r verwenden
Es wäre schön, wenn Sie zumindest einen Link zu einem [MCVE] hinterlassen würden, damit jeder, der bereit ist, Ihre Fragen zu beantworten, mit dem Code spielen kann. –
Sie können eine bessere Leistung finden, wenn Sie die Daten in einem Vektor speichern und dann sortieren, sobald der Vektor gefüllt ist. Es ist viel mehr Cache-freundlich und es sollte immer noch die gleiche Komplexität haben. – NathanOliver
@NathanOliver: Ich habe versucht, beide Optionen Benchmarking, mit Vektor + Post-Einfügung Sortierung nahm 15% mehr Zeit im Durchschnitt (50 Läufe). Es könnte aufgrund der Tatsache sein, dass das Array in der Größe klein bleiben: wenige Cache-Zugriff sind zu erwarten. die Funktion dagegen wird _sehr_ oft genannt. –