Distributing Monetary Amounts in C#

Categories: C#

Tags: Algorithms

Many times in financial applications, you will be tasked with distributing or allocating monetary amounts across a set of ratios (say, a 50/50 split or maybe a 30/70 split).  This can be tricky getting the rounding right so that no pennies are lost in the allocation.

Here’s an example:  split $0.05 in a 30/70 ratio.  The 30% amount becomes $0.015 and the 70% will be $0.035.  Now in this case, they both add up to the original amount (which is an absolute requirement) but they must have a half penny each to accomplish this.  We can’t have half pennies in this situation, so something has to be done with the extra penny.

Now the specifics on where you allocate the extra penny are up to your business requirements, so the solution I present below may not be exactly what you need.  It should, however, give you an idea on how to do this split without losing the extra penny.  Here’s a static method that will take a single monetary amount (as a C# decimal) and an array of ratios.  These ratios are your allocation percentages.  They could be the set [0.30, 0.70] or even [30, 70].  They don’t even need to sum to 1 or 100, it doesn’t matter:

public static decimal[] DistributeAmount(decimal amount, decimal[] ratios)
{
    decimal total = 0;
    decimal[] results = new decimal[ratios.Length];

    // find the total of the ratios
    for (int index = 0; index < ratios.Length; index++)
        total += ratios[index];

    // convert amount to a fixed point value (no mantissa portion)
    amount = amount * 100;
    decimal remainder = amount;
    for (int index = 0; index < results.Length; index++)
    {
        results[index] = Math.Floor(amount * ratios[index] / total);
        remainder -= results[index];
    }

    // allocate remainder across all amounts
    for (int index = 0; index < remainder; index++)
        results[index]++;

    // convert back to decimal portion
    for (int index = 0; index < results.Length; index++)
        results[index] = results[index] / 100;

    return results;
}

(Another thing here is that I am assuming pennies and dollars, or at least a currency system that divides their unit of currency into hundredths – notice the multiply by 100.  You can change that for universal currency systems to support any currency).

This code works by converting amounts to a fixed point value with no mantissa.  So in our example, $0.05 turns into 5.  We then iterate over each ratio and compute the amount to distribute using a simple division.  The trick here is the Math.Floor().  We round all half pennies down.  The half-penny will stay in the remainder variable. 

At the end of the distribution, we then distribute all of the fractional pennies that have built up evenly across the distributed amounts.  If there are no remaining pennies to distribute, it simply ends.  So in this implementation, the first ratios in the set tend to get the extra pennies and the last one loses out.  You can change this behavior to be almost anything you like (such as random, even-odd, or something else).

At the very end, we convert back to a decimal portion by dividing each amount by 100.

The final results for $0.05 would be { 0.02, 0.03 }, which adds up to 0.05.

No Comments