证明福勒的资金分配算法是正确的

发布于 2024-08-10 22:52:02 字数 960 浏览 7 评论 0原文

Martin Fowler 有一个 Money 类,它有一个货币分配例程。该例程根据给定的比率列表分配资金,而不会因舍入而损失任何值。它将所有余值分布到结果上。

例如,按“比率”(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;
}

为了解决这个问题,为了让它更简单,我冒昧地将 Money 类型替换为 long。)

问题是,我怎么知道它是正确的吗?除了最后的 for 循环之外,这一切似乎都是不言而喻的。我认为要证明该函数是正确的,只需在最后的 for 循环中证明以下关系成立就足够了:

remainder < results.length

有人能证明这一点吗?

Martin Fowler has a Money class that has a money allocation routine. This routine allocates money according to a given list of ratios without losing any value through rounding. It spreads any remainder value over the results.

For example, $100 allocated by the "ratios" (1, 1, 1) would yield ($34, $33, $33).

Here is the allocate function:

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;
}

(For the sake of this question, to make it simpler, I've taken the liberty of replacing the Money types with longs.)

The question is, how do I know it is correct? It all seems pretty self-evident except for the final for-loop. I think that to prove the function is correct, it would be sufficient to prove that the following relation is true in the final for-loop:

remainder < results.length

Can anyone prove that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不知在何时 2024-08-17 22:52:02

关键的见解是,计算每个结果[i]时,总余数等于各个余数的总和。

由于每个余数都是向下取整的结果,因此最多为 1。这样的余数有 results.length 个,因此总余数最多为 results.length

编辑:显然,如果没有一些漂亮的符号,这不是一个证明,所以这里有一些......
替代文本

The key insight is that the total remainder is equal to the sum of the individual remainders when calculating each result[i].

Since each individual remainder is the result of rounding down, it is at most 1. There are results.length such remainders, so the total remainder is at most results.length.

EDIT: Obviously it's not a proof without some pretty symbols, so here are some...
alt text

镜花水月 2024-08-17 22:52:02

无需证明。

基本金额通过简单除法分配,向下舍入。
因此分配的金额将始终小于或等于总数。

剩余部分包含未分配的金额。这始终是小于“i”的整数。所以他只是给每个接收者 1,直到钱用完为止。

No proof required.

The base amounts are allocated by simple division, rounding down.
So the allocated amount will always be less than or equal to the total.

Remainder contains the unallocated amount. Which will always be a whole number less than 'i'. So he simply gives each receiver 1 until the money is gone.

三月梨花 2024-08-17 22:52:02

简单

,只需使用

a=floor(a/b)*b+(a%b)

Simple

just use fact that

a=floor(a/b)*b+(a%b)

格子衫的從容 2024-08-17 22:52:02

我想说这是不正确的,因为某些奇怪的比率可能会导致余数大于结果数。因此我建议 results[i % results.length].amount++;.

编辑:我撤回我的答案。对于多头,没有奇怪的比率,对于浮点模没有帮助

I'd say it's not correct because some curious ratio could cause a remainder greater then the number of results. Therefore I suggest results[i % results.length].amount++;.

Edit: I withdraw my answer. With longs there's no curious ratio and with floating point modulo doesn't help

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文