Skip to content Skip to sidebar Skip to footer

Rounding Floats While Maintaining Total Sum Equal

I have a list of floats that add up to an integer. For circumstantial reasons, I have to iterate using a for loop x times, x being each float in the list, but since the argument fo

Solution 1:

I recently had to solve a similar problem and decided it was something common enough to various projects of mine to generalize a python solution and package it. Check out iteround.

Solution 2:

Ok, this is going to be a bit mathematical:

You have a series of real numbers Xi Their sum equals N sum(Xi) = N

Let's break each real number to its floor integer and residual real part (between 0 and 1): Xi = Ri + fi

Now, you need a series of integers Yi that are as close to Xi, but are integers and also sum to N. We can break them like this: Yi = Ri + Fi (where Fi is an integer either 0 or 1).

Now we need that: sum(Yi) = sum(Xi) = N

If you break that, you'll get this equation as a requirement for the solution: sum(Fi) = sum(fi) = N - sum(Ri)

Let's denote: K = N - sum(Ri)

Now the solution is simple, choose the K elements which have the largest fi values, and assign their corresponding Fi to 1; assign the other Fi to 0.

Now you have your values for Yi which in your case are the loop sizes

Here's the code for it:

defround_series_retain_integer_sum(xs):
    N = sum(xs)
    Rs = [round(x) for x in xs]
    K = N - sum(Rs)
    assert K == round(K)
    fs = [x - round(x) for x in xs]
    indices = [i for order, (e, i) inenumerate(reversed(sorted((e,i) for i,e inenumerate(fs)))) if order < K]
    ys = [R + 1if i in indices else R for i,R inenumerate(Rs)]
    return ys


xs = [5.2, 3.4, 2.1, 7.3, 3.25, 6.25, 8.2, 9.1, 10.1, 55.1]
ys = round_series_retain_integer_sum(xs)

print xs, sum(xs)
print ys, sum(ys)

I think I don't have any bugs, I hope you get the idea even if so

Post a Comment for "Rounding Floats While Maintaining Total Sum Equal"