Martin Fowler has a Money class有一个货币分配程序。该例程根据给定的比率列表分配资金,而不会通过舍入而损失任何价值。它会将任何余数值传播到结果上。
例如,按“比率”(1,1,1)分配的100美元将产生(34美元,33美元,33美元)。
以下是allocate
功能:
public long[] allocate(long amount, long[] ratios) {
long total = 0;
for (int i = 0; i < ratios.length; i++) total += ratios[i];
long remainder = amount;
long[] results = new long[ratios.length];
for (int i = 0; i < results.length; i++) {
results[i] = amount * ratios[i] / total;
remainder -= results[i];
}
for (int i = 0; i < remainder; i++) {
results[i]++;
}
return results;
}
(为了这个问题,为了使它更简单,我冒昧用long取代Money类型。)
问题是,我怎么知道它是正确的?除了最终的for-loop之外,这一切似乎都是不言而喻的。我认为为了证明函数是正确的,在最终的for循环中证明以下关系是正确的就足够了:
remainder < results.length
有人可以证明吗?
答案 0 :(得分:23)
关键的洞察力是,在计算每个result[i]
时,总余数等于各个余数的总和。
由于每个单独的余数是四舍五入的结果,因此最多为1.剩余results.length
个余数,因此总余数最多为results.length
。
编辑:显然,这不是一个没有漂亮符号的证明,所以这里有一些...
答案 1 :(得分:1)
无需证明。
基本金额通过简单划分,四舍五入。 因此,分配的金额将始终小于或等于总金额。
剩余包含未分配的金额。哪个总是比'i'少一整数。所以他只是给每个接收器1,直到钱不见了。
答案 2 :(得分:1)
简单
只使用
这个事实α=地板(A / B)* B +(A%B)
答案 3 :(得分:0)
我会说这不正确,因为一些奇怪的比例可能导致余数大于结果数。因此,我建议 results[i % results.length].amount++;
。
编辑:我撤回了我的回答。有多头没有好奇的比例,浮点模数没有帮助