2010-01-11 12 views
14

Potrzebuję napisać procedurę księgowania dla programu, który buduję, który da mi równy podział dziesiętny przez liczbę całkowitą. Tak, że na przykład:Równomiernie podzielić kwotę w dolarach (dziesiętnie) przez liczbę całkowitą

$143.13/5 = 

28.62 
28.62 
28.63 
28.63 
28.63 

Widziałem artykuł tutaj: Evenly divide in c#, ale wydaje się, że to działa tylko dla działów całkowitych. Masz pomysł na eleganckie rozwiązanie tego problemu?

+0

Integer podział jest wszystko, czego potrzebujemy. Nie powinieneś używać pływaków do pieniędzy. –

+0

Czy możesz rozwinąć? – Amberite

+5

Decimal to poprawny typ, którego należy tutaj użyć (inny niż float) – justinlatimer

Odpowiedz

29

Oblicz jedną ilości na raz, i odjąć każdą kwotę od sumy, aby upewnić się, że zawsze masz poprawną całkowitą lewej:

decimal total = 143.13m; 
int divider = 5; 
while (divider > 0) { 
    decimal amount = Math.Round(total/divider, 2); 
    Console.WriteLine(amount); 
    total -= amount; 
    divider--; 
} 

wynik:

28,63 
28,62 
28,63 
28,62 
28,63 
+2

To ładne rozwiązanie – Anurag

+3

Bardzo fajne! Oczywiście, uderz w Contract.Requires (total> = 0), ... divider> 0 lub jakakolwiek jest składnia, aby uczynić to jeszcze bardziej eleganckim. A potem przetestowałbym to urządzenie na śmierć ... nie boli. Testy jednostkowe nie muszą działać szybko, więc uzyskaj odpowiedź, a następnie posortuj ją i porównaj z oczekiwanym wynikiem. Ponadto zwróciłbym kwotę, zamiast drukować ją w rzeczywistej implementacji. Dodałbym inną funkcję, która, jak przypuszczam, zwraca wynik jako tablicę ... dziesiętnych. Ponieważ znasz dzielnik, możesz przydzielić tablicę o wymaganym dokładnym rozmiarze. –

+0

Dzięki, że wygląda to ładne, eleganckie rozwiązanie! – Amberite

1

Możesz użyć algorytmu w pytaniu, do którego się odwołujemy, pomnażając przez 100, używając funkcji równomiernie dzielonej liczby całkowitej, a następnie dzieląc każdy z wyników przez 100 (zakładając, że chcesz obsłużyć tylko 2 dp, jeśli chcesz 3DP wielokrotność przez 1000 etc)

+0

Podobnie jak w przypadku reakcji Nicka, to straci kilka centów (w podanym przykładzie) – danben

2

Jeśli masz pływak, który jest gwarantowany dokładnie dwie cyfry precyzja, co na ten temat (pseudokod):

amount = amount * 100 (convert to cents) 
int[] amounts = new int[divisor] 
for (i = 0; i < divisor; i++) amounts[i] = amount/divisor 
extra = amount % divisor 
for (i = 0; i < extra; i++) amounts[i]++ 

a potem rób co chcesz z amounts, które są w centów - można było zamienić z powrotem na pływaki, jeśli absolutnie trzeba, lub sformatować jako dolary i centy.

Jeśli nie jest jasne, celem tego wszystkiego nie jest równomierne podzielenie wartości zmiennoprzecinkowej, ale równomierne podzielenie kwoty pieniężnej, biorąc pod uwagę, że centy są niepodzielną jednostką USD. Do PO: daj mi znać, jeśli nie tego chcesz.

+3

Pływak jest źle źle ... nigdy nie powinien polecać pływać za pieniądze –

+4

To nie moja wina, że ​​OP mówi, że zaczyna od pływaków. Gdybyś miał ochotę przeczytać moją odpowiedź, zamiast ślepo modować, zobaczyłbyś, że od razu zamieniłem ją na int. – danben

26

można rozwiązać ten (w centach) bez konstruowaniu tablicy:

int a = 100 * amount; 
int low_value = a/n; 
int high_value = low_value + 1; 
int num_highs = a % n; 
int num_lows = n - num_highs; 
+0

Nie mam pojęcia, dlaczego pierwszy głosowałem. Myślę, że jest to najbardziej intuicyjny i skuteczny sposób na zrobienie tego. – Ponkadoodle

+0

+1, to jest moja odpowiedź, ale lepiej. – danben

+0

+1. To zadziałało doskonale dla mnie w funkcji bazy danych, gdzie inne rozwiązania oparte na pętlach byłyby problemem wydajności. – dpw

3

łatwiej radzić sobie z CEN ts. Sugeruję, że zamiast 143,13 dzielisz 14313 na 5 równych części. Co daje 2862 i pozostałą 3. Możesz przypisać tę resztę do pierwszych trzech części lub w dowolny sposób. Wreszcie, zamień centów z powrotem na dolary.

Zauważ, że zawsze otrzymasz pozostałą część mniej niż liczba części, które chcesz.

3

Przede wszystkim upewnij się, że nie używasz liczby zmiennoprzecinkowej do reprezentowania dolarów i centów (zobacz inne posty z tego powodu, ale prostym powodem jest to, że nie wszystkie liczby dziesiętne mogą być reprezentowane jako zmienne, np. 1,79 USD).

Oto jeden sposób to zrobić:

decimal total = 143.13m; 
int numberOfEntries = 5; 
decimal unadjustedEntryAmount = total/numberOfEntries; 
decimal leftoverAmount = total - (unadjustedEntryAmount * numberOfEntries); 
int numberOfPenniesToDistribute = leftoverAmount * 100; 
int numberOfUnadjustedEntries = numberOfEntries - numberOfPenniesToDistribute; 

Więc teraz masz niedostosowanej ilości 28.62, a potem trzeba zdecydować, jak rozłożyć resztę. Możesz rozprowadzić dodatkową pensę za każdą rozpoczętą u góry lub u dołu (wygląda na to, że chcesz od dołu).

for (int i = 0; i < numberOfUnadjustedEntries; i++) { 
    Console.WriteLine(unadjustedEntryAmount); 
} 

for (int i = 0; i < numberOfPenniesToDistribute; i++) { 
    Console.WriteLine(unadjustedEntryAmount + 0.01m); 
} 

Możesz również dodać całą resztę do pierwszego lub ostatniego wpisu. Wreszcie, w zależności od potrzeb księgowych, możesz również utworzyć oddzielną transakcję dla pozostałej części.

1

Możliwe jest również, aby użyć C# generacji iterator aby Guffa's answer wygodniejsze:

public static IEnumerable<decimal> Divide(decimal amount, int numBuckets) 
{ 
    while(numBuckets > 0) 
    { 
     // determine the next amount to return... 
     var partialAmount = Math.Round(amount/numBuckets, 2); 
     yield return partialAmount; 
     // reduce th remaining amount and #buckets 
     // to account for previously yielded values 
     amount -= partialAmount; 
     numBuckets--; 
    } 
} 
Powiązane problemy