animal_magics Antwort ist richtig, dass Sie die Zahlen vom kleinsten zum größten addieren sollten, aber ich möchte ein Beispiel geben, um zu zeigen, warum.
Angenommen, wir arbeiten in einem Gleitkommaformat, das uns eine erstaunliche Genauigkeit von 3 Stellen bietet. Nun wollen wir zehn Zahlen hinzufügen:
[1000, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Natürlich ist die genaue Antwort 1009, aber wir können das nicht in unserem 3-stelligen Format bekommen. Die genaueste Antwort, die wir bekommen, ist 1010, auf 3 Stellen gerundet. Wenn wir die kleinste zur größten addieren, bekommen wir auf jeder Schleife:
Loop Index s
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 1009 -> 1010
So erhalten wir die genauestmögliche Antwort für unser Format. Nehmen wir nun an, wir addieren vom größten zum kleinsten.
Loop Index s
1 1000
2 1001 -> 1000
3 1001 -> 1000
4 1001 -> 1000
5 1001 -> 1000
6 1001 -> 1000
7 1001 -> 1000
8 1001 -> 1000
9 1001 -> 1000
10 1001 -> 1000
Da die Gleitkommazahlen nach jeder Operation gerundet werden, werden alle Additionen abgerundet, wodurch sich unser Fehler von 1 auf 9 genau erhöht. Stellen Sie sich nun vor, Ihre hinzuzufügende Zahlenreihe hätte 1000 und dann hundert Einsen oder eine Million. Beachten Sie, dass Sie, um wirklich genau zu sein, die kleinsten zwei Zahlen summieren und dann das Ergebnis in Ihre Zahlenmenge umwandeln möchten.
Die vorherigen Antworten behandeln die Angelegenheit bereits allgemein und geben fundierte Ratschläge, aber es gibt noch eine weitere Besonderheit, die ich erwähnen möchte. Auf den meisten modernen Architekturen würde die von
for
Ihnen beschriebene Schleife ohnehin mit einer erweiterten Genauigkeit von 80 Bit ausgeführt , was eine zusätzliche Genauigkeit garantiert, da alle temporären Variablen in Registern abgelegt werden. Sie haben also bereits eine Art Schutz vor numerischen Fehlern. In komplizierteren Schleifen werden die Zwischenwerte jedoch zwischen den Operationen im Speicher gespeichert und daher auf 64 Bit gekürzt. Ich vermute, dassDies reicht aus, um eine geringere Genauigkeit in der Summierung zu erzielen (!!). Seien Sie also sehr vorsichtig, wenn Sie Ihren Code drucken und debuggen möchten, während Sie die Richtigkeit überprüfen.
Für die Interessierten beschreibt dieser Aufsatz ein Problem in einer weit verbreiteten numerischen Routine (Lapacks rangaufschlussreiche QR-Faktorisierung), deren Debugging und Analyse gerade aufgrund dieses Problems sehr schwierig war.
quelle
Von den beiden Optionen führt das Hinzufügen von kleiner zu größer zu weniger numerischen Fehlern als das Hinzufügen von größer zu kleiner.
Vor> 20 Jahren in meiner Klasse "Numerische Methoden" gab der Ausbilder dies jedoch an und mir fiel auf, dass dies immer noch mehr Fehler verursachte als notwendig, da der relative Wertunterschied zwischen dem Akkumulator und den hinzugefügten Werten bestand.
Eine logische Lösung besteht darin, die 2 kleinsten Zahlen in die Liste einzufügen und den summierten Wert erneut in die sortierte Liste einzufügen.
Um dies zu demonstrieren, habe ich einen Algorithmus entwickelt, der dies effizient (räumlich und zeitlich) durchführen kann, indem der freiwerdende Speicherplatz verwendet wird, wenn Elemente aus dem primären Array entfernt werden, um ein sekundäres Array der seit den Additionen inhärent geordneten summierten Werte zu erstellen waren von der Summe der Werte, die immer größer wurden. Bei jeder Iteration werden dann die "Spitzen" beider Arrays überprüft, um die 2 kleinsten Werte zu finden.
quelle
Da Sie den zu verwendenden Datentyp nicht eingeschränkt haben, verwenden Sie einfach Zahlen mit beliebiger Länge, um ein perfektes Ergebnis zu erzielen. In diesem Fall spielt die Reihenfolge keine Rolle. Es wird viel langsamer sein, aber Perfektion zu erreichen, braucht Zeit.
quelle
Verwenden Sie die Binärbaumaddition, dh wählen Sie den Mittelwert der Verteilung (nächste Zahl) als Wurzel des Binärbaums und erstellen Sie einen sortierten Binärbaum, indem Sie links im Diagramm kleinere und rechts größere Werte usw. hinzufügen . Das rekursive Hinzufügen aller untergeordneten Knoten eines einzelnen übergeordneten Knotens in einem Bottom-Up-Ansatz. Dies ist effizient, da der durchschnittliche Fehler mit der Anzahl der Summierungen zunimmt, und in einem Binärbaumansatz liegt die Anzahl der Summierungen in der Größenordnung von log n in der Basis 2. Daher wäre der durchschnittliche Fehler geringer.
quelle
Was Hristo Iliev oben über 64-Bit-Compiler gesagt hat, die die SSE- und AVX-Anweisungen gegenüber der FPU (AKA NDP) bevorzugen, ist zumindest für Microsoft Visual Studio 2013 absolut richtig Es ist tatsächlich schneller und theoretisch auch genauer, die FPU zu verwenden. Wenn es Ihnen wichtig ist, würde ich vorschlagen, zuerst verschiedene Lösungen zu testen, bevor Sie sich für einen endgültigen Ansatz entscheiden.
Wenn ich in Java arbeite, verwende ich sehr häufig den BigDecimal-Datentyp mit willkürlicher Genauigkeit. Es ist einfach zu einfach und man merkt normalerweise nicht, dass die Geschwindigkeit abnimmt. Das Berechnen der transzendentalen Funktionen mit unendlichen Reihen und sqrt nach der Newton-Methode kann eine Millisekunde oder länger dauern, ist aber machbar und ziemlich genau.
quelle
Ich habe dies nur hier gelassen /programming//a/58006104/860099 (wenn Sie dorthin gehen, klicken Sie auf "Code-Snippet anzeigen" und führen Sie es über die Schaltfläche aus
Es ist ein JavaScript-Beispiel, das deutlich zeigt, dass die Summe ab dem größten Fehler größer ist
quelle