Равномерно делить сумму в долларах (десятичную) на целое число
Мне нужно написать процедуру учета для создаваемой мной программы, которая даст мне четное деление десятичного числа на целое число. Так что, например:
$143.13 / 5 =
28.62
28.62
28.63
28.63
28.63
Я видел статью здесь: Равно разделить на С#, но похоже, что она работает только для целых делений. Любая идея элегантного решения этой проблемы?
Ответы
Ответ 1
Вычислите суммы по одному и вычтите каждую сумму из общей суммы, чтобы убедиться, что у вас всегда есть правильная сумма слева:
decimal total = 143.13m;
int divider = 5;
while (divider > 0) {
decimal amount = Math.Round(total / divider, 2);
Console.WriteLine(amount);
total -= amount;
divider--;
}
результат:
28,63
28,62
28,63
28,62
28,63
Ответ 2
Вы можете решить эту проблему (в центах) без построения массива:
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;
Ответ 3
Легче иметь дело с центами. Я бы предположил, что вместо 143.13 вы разделите 14313 на 5 равных частей. Это дает вам 2862 и оставшуюся часть 3. Вы можете назначить этот остаток первым трем частям или любым другим способом. Наконец, конвертируйте центы обратно в доллары.
Также обратите внимание, что вы всегда получите остаток меньше, чем количество частей, которые вы хотите.
Ответ 4
Прежде всего, убедитесь, что вы не используете число с плавающей запятой, чтобы представлять доллары и центы (см. другие сообщения для почему, но простая причина заключается в том, что не все десятичные числа могут быть представлены как float, например, $1,79).
Вот один из способов сделать это:
decimal total = 143.13m;
int numberOfEntries = 5;
decimal unadjustedEntryAmount = total / numberOfEntries;
decimal leftoverAmount = total - (unadjustedEntryAmount * numberOfEntries);
int numberOfPenniesToDistribute = leftoverAmount * 100;
int numberOfUnadjustedEntries = numberOfEntries - numberOfPenniesToDistribute;
Итак, теперь у вас есть нескорректированное количество 28,62, и тогда вам нужно решить, как распределить остаток. Вы можете либо распределить дополнительный пенни каждому, начиная сверху или снизу (похоже, что вы хотите снизу).
for (int i = 0; i < numberOfUnadjustedEntries; i++) {
Console.WriteLine(unadjustedEntryAmount);
}
for (int i = 0; i < numberOfPenniesToDistribute; i++) {
Console.WriteLine(unadjustedEntryAmount + 0.01m);
}
Вы также можете добавить весь остаток к первой или последней записи. Наконец, в зависимости от потребностей в учетной записи вы также можете создать отдельную транзакцию для остальных.
Ответ 5
Если у вас есть float, которому гарантируется ровно две цифры точности, что об этом (псевдокод):
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]++
а затем сделайте все, что хотите, с помощью amounts
, которые находятся в центах - вы можете конвертировать обратно в float, если вам абсолютно необходимо, или форматировать в долларах и центах.
Если это не ясно, точка всего этого заключается не только в том, чтобы разделить значение поплавка равномерно, а на то, чтобы разделить денежную сумму как можно более равномерно, учитывая, что центы являются неделимой единицей USD. OP: дайте мне знать, если это не то, что вы хотели.
Ответ 6
Вы можете использовать алгоритм в вопросе, на который вы ссылаетесь, путем умножения на 100, используя функцию равномерного разделения целого числа, а затем разделив каждый из результатов на 100 (предполагая, что вы хотите обрабатывать только 2 dp, если вы хотите, чтобы 3dp несколько на 1000 и т.д.)
Ответ 7
Взгляните на этот вопрос: Каков наилучший тип данных для использования в С#?
Подождите секунду! Вы хотите убедиться, что ни один цент не потеряется, не так ли?
Ответ 8
Также возможно использовать генерацию итератора С#, чтобы сделать ответ Guffa более удобным:
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--;
}
}