Das Ziel der Rundung ist es, die geringste Fehlermenge zu erzeugen. Wenn Sie einen einzelnen Wert runden, ist dieser Prozess einfach und unkompliziert, und die meisten Menschen verstehen ihn leicht. Wenn Sie mehrere Zahlen gleichzeitig runden, wird der Prozess schwieriger - Sie müssen definieren, wie die Fehler kombiniert werden sollen, dh was minimiert werden muss.
Die gut gewählte Antwort von Varun Vohra minimiert die Summe der absoluten Fehler und ist sehr einfach zu implementieren. Es gibt jedoch Randfälle, die nicht behandelt werden - was sollte das Ergebnis einer Rundung sein?24.25, 23.25, 27.25, 25.25
? Eine davon muss aufgerundet statt abgerundet werden. Sie würden wahrscheinlich nur willkürlich den ersten oder letzten in der Liste auswählen.
Vielleicht ist es besser, den relativen Fehler anstelle des absoluten zu verwenden Fehlers zu verwenden. Durch Runden von 23,25 auf 24 wird es um 3,2% geändert, während durch Runden von 27,25 auf 28 nur um 2,8% geändert wird. Jetzt gibt es einen klaren Gewinner.
Es ist möglich, dies noch weiter zu optimieren. Eine übliche Technik ist zu quadrieren jeden Fehler, so dass große Fehler zählen unverhältnismäßig mehr als kleine. Ich würde auch einen nichtlinearen Divisor verwenden, um den relativen Fehler zu erhalten - es scheint nicht richtig, dass ein Fehler bei 1% 99-mal wichtiger ist als ein Fehler bei 99%. Im folgenden Code habe ich die Quadratwurzel verwendet.
Der vollständige Algorithmus lautet wie folgt:
- Summieren Sie die Prozentsätze, nachdem Sie sie alle abgerundet haben, und subtrahieren Sie sie von 100. Hier erfahren Sie, wie viele dieser Prozentsätze stattdessen aufgerundet werden müssen.
- Generieren Sie zwei Fehlerwerte für jeden Prozentsatz, einen beim Abrunden und einen beim Aufrunden. Nehmen Sie den Unterschied zwischen den beiden.
- Sortieren Sie die oben erzeugten Fehlerunterschiede.
- Nehmen Sie für die Anzahl der Prozentsätze, die aufgerundet werden müssen, ein Element aus der sortierten Liste und erhöhen Sie den abgerundeten Prozentsatz um 1.
Sie können beispielsweise immer noch mehr als eine Kombination mit derselben Fehlersumme haben 33.3333333, 33.3333333, 33.3333333
. Dies ist unvermeidlich und das Ergebnis ist völlig willkürlich. Der Code, den ich unten gebe, rundet die Werte auf der linken Seite lieber auf.
So sieht es in Python aus.
def error_gen(actual, rounded):
divisor = sqrt(1.0 if actual < 1.0 else actual)
return abs(rounded - actual) ** 2 / divisor
def round_to_100(percents):
if not isclose(sum(percents), 100):
raise ValueError
n = len(percents)
rounded = [int(x) for x in percents]
up_count = 100 - sum(rounded)
errors = [(error_gen(percents[i], rounded[i] + 1) - error_gen(percents[i], rounded[i]), i) for i in range(n)]
rank = sorted(errors)
for i in range(up_count):
rounded[rank[i][1]] += 1
return rounded
>>> round_to_100([13.626332, 47.989636, 9.596008, 28.788024])
[14, 48, 9, 29]
>>> round_to_100([33.3333333, 33.3333333, 33.3333333])
[34, 33, 33]
>>> round_to_100([24.25, 23.25, 27.25, 25.25])
[24, 23, 28, 25]
>>> round_to_100([1.25, 2.25, 3.25, 4.25, 89.0])
[1, 2, 3, 4, 90]
Wie Sie an diesem letzten Beispiel sehen können, kann dieser Algorithmus immer noch nicht intuitive Ergebnisse liefern. Obwohl 89.0 keinerlei Rundung benötigt, musste einer der Werte in dieser Liste aufgerundet werden. Der niedrigste relative Fehler ergibt sich aus der Aufrundung dieses großen Werts und nicht aus den viel kleineren Alternativen.
Diese Antwort befürwortete ursprünglich, jede mögliche Kombination von Aufrunden / Abrunden durchzugehen, aber wie in den Kommentaren ausgeführt, funktioniert eine einfachere Methode besser. Der Algorithmus und der Code spiegeln diese Vereinfachung wider.