2009-11-05 15 views
14

Martin Fowler has a Money class, der eine Geldzuweisungsroutine hat. Diese Routine teilt Geld gemäß einer gegebenen Liste von Verhältnissen zu, ohne irgendeinen Wert durch Runden zu verlieren. Es verteilt jeden Restwert über die Ergebnisse.Beweisen Sie, dass Fowlers Geldallokationsalgorithmus korrekt ist

Zum Beispiel würde $ 100 durch die "Ratios" (1, 1, 1) zugewiesen ergeben ($ 34, $ 33, $ 33). Hier

ist die allocate Funktion:

public long[] allocate(long amount, long[] ratios) { 
    long total = 0; 
    for (int i = 0; i < ratios.length; i++) total += ratios[i]; 

    long remainder = amount; 
    long[] results = new long[ratios.length]; 
    for (int i = 0; i < results.length; i++) { 
     results[i] = amount * ratios[i]/total; 
     remainder -= results[i]; 
    } 

    for (int i = 0; i < remainder; i++) { 
     results[i]++; 
    } 

    return results; 
} 

(. Für die Zwecke dieser Frage, es einfacher zu machen, habe ich mir die Freiheit für den Ersatz der Geldtypen mit longs genommen)

Die Frage ist, woher weiß ich, dass es richtig ist? Alles scheint ziemlich selbstverständlich zu sein, außer für die finale For-Schleife. Ich denke, dass die Funktion zu beweisen, richtig ist, wäre es ausreichend, um zu beweisen, daß die folgende Beziehung in dem endgültigen for-Schleife erfüllt ist:

remainder < results.length 

Kann das jemand beweisen?

+1

Angenommen, Sie möchten die X-Nummer in Y-Teile aufteilen. Die Erinnerung ist X% Y, was immer

Antwort

21

Die wichtigste Erkenntnis ist, dass der Gesamtrest gleich der Summe der einzelnen Reste bei der Berechnung jeder result[i] ist.

Da jeder einzelne Rest das Ergebnis der Abrundung ist, ist es höchstens 1. Es gibt results.length solche Reste, so dass der Gesamtrest höchstens results.length ist.

EDIT: Offensichtlich ist es nicht ein Beweis, ohne ein paar ziemlich Symbole, so dass hier einige sind ...
alt text

+0

Ja, das war der Teil, den ich vermisste. Danke. –

+0

+1. Beachten Sie, dass das letzte '<' '' '' sein sollte, da '\ sum_ {i = 1}^k 1 = k'. – Stephan202

+0

Also sollte es - das ist, was ich bekomme, um es auf weniger Zeilen zusammenzufassen. Es hat ursprünglich "Rest stevemegson

0

Ich würde sagen, es ist nicht korrekt, weil ein seltsames Verhältnis einen Rest verursachen könnte, der größer ist als die Anzahl der Ergebnisse. Daher schlage ich results[i % results.length].amount++; vor.

Edit: Ich ziehe meine Antwort zurück. Mit longs gibt es kein merkwürdiges Verhältnis und mit Fließkomma hilft modulo nicht

+0

Ich würde dem widersprechen müssen. Diese seltsame Ration ist mathematisch unmöglich. –

+0

Für die Menge der ganzen Zahlen gibt es kein "merkwürdiges" Verhältnis. –

+0

Ja, für lange gibt es keins. Aber die OP-Longs werden in diesem Beispiel nur der Einfachheit halber verwendet. Und wir alle wissen, dass man doppelte Werte nicht ohne Fehlerquote vergleichen sollte.Deshalb können in einem Computerprogramm merkwürdige Verhältnisse auftreten, wegen dieses Fehlerverhältnisses – DaClown

1

Kein Beweis erforderlich.

Die Basisbeträge werden durch einfache Division, Abrunden zugeordnet. Der zugewiesene Betrag wird also immer kleiner oder gleich dem Gesamtbetrag sein.

Rest enthält die nicht zugewiesene Menge. Das wird immer eine ganze Zahl weniger als 'ich' sein. Also gibt er jedem Empfänger einfach 1, bis das Geld weg ist.

+1

dass der zugewiesene Betrag <= der Gesamtbetrag ist klar, aber warum ist es garantiert

+0

Es ist nicht <=, es ist nur <('weniger'). Wenn der zugewiesene Betrag gleich ist, würde die Abteilung das Ergebnis perfekt teilen, nicht wahr? 4% 2 ist nicht 1 mit Erinnerung 2 und wird es nie sein. –

+1

Wenn Sie $ 99 mit Ratios (1,1,1) zuweisen, weist der erste Schritt des Algorithmus 99 zu, sodass der vom ersten Schritt zugewiesene Schritt tatsächlich dem Gesamtbetrag entsprechen kann. Aber das ist nicht wirklich meine Frage. Was ich nicht verstehe, ist warum die nicht zugewiesene Menge (im ersten Schritt) kleiner ist als #Ratios. –

0

Einfache

gerade Tatsache nutzen, dass

a = Boden (a/b) * b + (a% b)

Verwandte Themen