通过算法分割账单&公平,之后:)
我正在尝试解决您可能遇到的以下现实生活问题:
您与一些朋友共进晚餐,并且你们都同意平摊账单。只是当账单最终到达时,你会发现并不是每个人都有足够的现金(如果有的话,都是便宜的混蛋)。
所以,你们中的一些人比其他人支付更多……之后,您回家并尝试决定“谁欠谁多少钱?”。
我正在尝试通过算法来解决这个问题公平:)
一开始看起来很容易,但我陷入了四舍五入的困境,我感觉自己像个彻底的失败者;)
关于如何解决这个问题有什么想法吗?
编辑:一些Python代码来显示我的困惑
>>> amounts_paid = [100, 25, 30]
>>> total = sum(amounts_paid)
>>> correct_amount = total / float(len(amounts_paid))
>>> correct_amount
51.666666666666664
>>> diffs = [amnt-correct_amount for amnt in amounts_paid]
>>> diffs
[48.333333333333336, -26.666666666666664, -21.666666666666664]
>>> sum(diffs)
7.1054273576010019e-015
理论上,差异之和应该为零,对吧?
另一个例子它有效:)
>>> amounts_paid = [100, 50, 150]
>>> total = sum(amounts_paid)
>>> correct_amount = total / float(len(amounts_paid))
>>> correct_amount
100.0
>>> diffs = [amnt-correct_amount for amnt in amounts_paid]
>>> diffs
[0.0, -50.0, 50.0]
>>> sum(diffs)
0.0
I'm trying to solve the following real-life problem you might have encountered yourselves:
You had dinner with some friends and you all agreed to split the bill evenly. Except that when the bill finally arrives, you find out not everyone has enough cash on them (if any, cheap bastards).
So, some of you pays more than others... Afterwards you come home and try to decide "who owes who what amount?".
This, I'm trying to solve algorithmically & fair :)
it seems so easy at first, but I'm getting stuck with rounding and what not, I feel like a total loser ;)
Any ideas on how to tackle this?
EDIT: Some python code to show my confusion
>>> amounts_paid = [100, 25, 30]
>>> total = sum(amounts_paid)
>>> correct_amount = total / float(len(amounts_paid))
>>> correct_amount
51.666666666666664
>>> diffs = [amnt-correct_amount for amnt in amounts_paid]
>>> diffs
[48.333333333333336, -26.666666666666664, -21.666666666666664]
>>> sum(diffs)
7.1054273576010019e-015
Theoratically, the sum of the differences should be zero, right?
for another example it works :)
>>> amounts_paid = [100, 50, 150]
>>> total = sum(amounts_paid)
>>> correct_amount = total / float(len(amounts_paid))
>>> correct_amount
100.0
>>> diffs = [amnt-correct_amount for amnt in amounts_paid]
>>> diffs
[0.0, -50.0, 50.0]
>>> sum(diffs)
0.0
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
http://www.billmonk.com/
其中。问题已经解决了。很多次了。
是的。然而,由于您使用了
float
,因此当人数不是 2 的幂时,您就会遇到表示问题。绝不。使用。
浮动
对于。金融。从不
总是。使用。
十进制
对于。金融。永远
http://www.billmonk.com/
Amongst others. The problem has already been solved. Many times over.
Yes. Since you've used
float
, however, you have representation issues when the number of people is not a power of two.Never. Use.
float
For. Finance.Never
Always. Use.
decimal
For. Finance.Always
诀窍是将每个人视为一个单独的帐户。
您可以(根据原始账单)轻松确定每个人应支付的金额。将此设置为每个人的负数。接下来,通过将支付到每个人的帐户的金额相加来记录每个人已支付的金额。此时,多付的人(贷方)将有正余额,而少付的人(借款人)将有负余额。
对于哪个借款人欠每个贷款人的钱,没有一个正确的答案,除非在只有一个贷款人的明显情况下。借款人支付的金额可以流向任何贷款人。只需将金额添加到借款人的总额中,然后减去收到付款的贷方的金额即可。
当所有账户都归零时,所有人都已付款。
编辑(回应评论):
在处理美元和美分时,没有 100% 干净的方法来处理舍入。有些人会比其他人多付一分钱。唯一公平的方法是随机分配额外的 0.01 美元(根据要求)。这只需要执行一次,即通过划分帐单来计算“欠款金额”时。有时,它有助于将货币价值存储为美分,而不是美元(例如,12.34 美元将存储为 1234)。这使您可以使用整数而不是浮点数。
要分配额外的美分,我会执行以下操作:
注意:“随机”分配便士的最简单方法是将第一个额外的美分分配给第一个人,第二个额外的美分分配给第二个人,依此类推如果您始终以相同的顺序输入相同的人员,这只会成为问题。
The trick is to treat each person as a separate account.
You can easily determine (from the original bill) how much each person should pay. Set this as a negative amount for each person. Next, record the amount that each person has paid by adding the amount paid to their account. At this point, the people who have overpaid (lenders) will have positive balances, and the people who have underpaid (borrowers) will have negative balances.
There is no one right answer to which borrower owes money to each lender, except in the obvious case where there is only one lender. Amounts paid by a borrower can go to any of the lenders. Simply add the amount to the borrower's total, and subtract amounts from the lenders who receive the payment.
When all accounts hit zero, everyone has paid up.
Edit (in response to comments):
When dealing with dollars and cents, there is no 100% clean way to handle the rounding. Some people will pay one cent more than others. The only way to be fair is to assign the extra $0.01 at random (as required). This would be done only once, when the "amount owed" is being calculated by dividing up the bill. It sometimes helps to store monetary values as cents, not as dollars ($12.34 would be stored as 1234, for example). This lets you use integers instead of floats.
To distribute the extra cents, I would do the following:
Note: the easiest way to assign the pennies "randomly" is to assign the first extra cent to the first person, the second to the second, etc. This only becomes a problem if you always enter the same people in the same order.
我不是一个Python爱好者,但我发现这是一个有趣的问题=)这是我的解决方案。开发时间约 45 分钟。我编写干净的 perl...应该很容易移植。
I'm not a python guy, but I found it an interesting problem =) Here's my solution. Dev time ~45min. I write clean perl... should be easy to port.
你知道每个人所欠的总额,以及谁欠缺的。把每个人的总空头金额从最高的多付者到最低的人分配给那些支付更多的人。
You know the total everyone owed, and who was short. Take that total short that everyone was and divy it out to those who paid more, starting from the highest overpayer to lowest.
您看到的“问题”与浮点数的二进制表示有关,如此处。无论如何,7.1054273576010019e-015 是一个非常非常小的数字,因此,如果您将结果四舍五入到最接近的分(正如您应该做的那样),就不会有任何问题。
The "problem" you are seeing has to do with binary representation of floating-point numbers as explained here. At any rate, 7.1054273576010019e-015 is a tiny, tiny number, so if you round your results to the nearest cent, as you should, you wouldn't have any problems.