I have a system which calculates different costs for a number of people when splitting a cost. For example Person A buys something for 10 and Persons B, C, and D should split the cost.

The system should therefor register a positive record for person A of 10 and negative records of 10/3 for B, C and D.

However, when this is done; B, C and D all have -3.33 after rounding. Which of course doesn't add up to the total of 10. What's the best way of going about this problem? An optimal solution would randomise what person get's the slightly bigger cost as well.

One possible solution is if I just let the last person's debt be 10 - (A + B), but then there's a problem if four persons split a cost of for example 13.34. The different parts would then be 3.34, 3.34, 3.34 and 3.32, whereas the optimal split would be 3.34, 3.34, 3.33, 3.33.

Some might argue that with sufficient decimals this is only a problem when having vast amounts of rows. But in an economical system I think it's important to have a fail-safe system even from the start. It needs to be scalable, and can't have even the slightest error. Unfairness is alright, just not errors.

I think I would find the two closest dividing values, then toggle between the two as they are assigned. Then figure out what to do with the (potential) last odd value.
–
SmandoliJul 23 '12 at 12:11

This is how every question should look :). Very well described. +1 from me.
–
y2okJul 23 '12 at 14:44

1

With money involved, I think fairness ends up always being important--if your system consistently overcharges a certain class of users (based on e.g. ID number, registration date, alphabetized names, or however else your database sorts records), there's some potential for a class action. One fair approach would be to randomly pick a user to charge from the list of users not yet charged, each time you calculate a charge amount.
–
Theodore MurdockJul 23 '12 at 15:20

Thank you very much! A few questions though: 1. when casting $payment as an int, does it result in 3.33 or 3.34, ie. rounded or not? 2. When trying different values in your wonderful js-script I can get values that are not rounded to two decimals. Should I do a similar int-cast somewhere in the if-statement?
–
Per EnströmJul 23 '12 at 14:28

1) It will result in 3.33. 2) Can you give me some examples?
–
y2okJul 23 '12 at 14:31

Maybe make a new "rounding balance" up for every user. If it was 10 to be split three ways, then each user would pay 3.34. Each user would also have 2/3 of a cent to their rounding balance. (this would have to be stored as text I presume) .

Next time the same thing happens, check the rounding balance.. They have 2/3 of a cent, so now you can take one third off (so they now have 1/3 of a cent in the rounding balance ) and only charge 3.33 .