Let's say I have an array of floating point numbers, in sorted (let's say ascending) order, whose sum is known to be an integer N
. I want to "round" these numbers to integers while leaving their sum unchanged. In other words, I'm looking for an algorithm that converts the array of floating-point numbers (call it fn
) to an array of integers (call it in
) such that:
- the two arrays have the same length
- the sum of the array of integers is
N
- the difference between each floating-point number
fn[i]
and its corresponding integerin[i]
is less than 1 (or equal to 1 if you really must) - given that the floats are in sorted order (
fn[i] <= fn[i+1]
), the integers will also be in sorted order (in[i] <= in[i+1]
)
Given that those four conditions are satisfied, an algorithm that minimizes the rounding variance (sum((in[i] - fn[i])^2)
) is preferable, but it's not a big deal.
Examples:
[0.02, 0.03, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14] => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] [0.1, 0.3, 0.4, 0.4, 0.8] => [0, 0, 0, 1, 1] [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] => [0, 0, 0, 0, 0, 0, 0, 0, 0, 1] [0.4, 0.4, 0.4, 0.4, 9.2, 9.2] => [0, 0, 1, 1, 9, 9] is preferable => [0, 0, 0, 0, 10, 10] is acceptable [0.5, 0.5, 11] => [0, 1, 11] is fine => [0, 0, 12] is technically not allowed but I'd take it in a pinch
EDIT: Wow, I wasn't expecting such a strong response overnight! I clarified the conditions above. To answer some excellent questions raised in the comments:
- Repeated elements are allowed in both arrays (although I would also be interested to hear about algorithms that work only if the array of floats does not include repeats)
- There is no single correct answer - for a given input array of floats, there are generally multiple arrays of ints that satisfy the four conditions.
- The application I had in mind was - and this is kind of odd - distributing points to the top finishers in a game of MarioKart ;-) Never actually played the game myself, but while watching someone else I noticed that there were 24 points distributed among the top 4 finishers, and I wondered how it might be possible to distribute the points according to finishing time (so if someone finishes with a large lead they get a larger share of the points). The game tracks point totals as integers, hence the need for this kind of rounding.