# 民调百分比的四舍五入存在不精确性

**URL:** https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319
**Category:** Feature
**Created:** [2016 年11 月 1 日 18:39 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319 "2016-11-01T18:39:14Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![rizka](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rizka/32/79717_2.png) [@rizka](https://meta.discourse.org/u/rizka)
#### Post date: [2016 年11 月 1 日 18:39 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/1 "2016-11-01T18:39:14Z")

</div>

续接 [投票中百分比的四舍五入不准确](https://meta.discourse.org/t/rounding-of-percentages-on-polls-is-inaccurate/50376/2) 的讨论：

我决定开一个新话题，因为最新的问题并非关于有争议的舍入规则，而是完全错误的规则。因此，这个话题必须归类到 #Contribute > Bug 类别。虽然不是什么大问题，但确实有些尴尬。

我们进行了一次公开投票，共有 106 票。其中 69 票投给“否”，37 票投给“是”。简单的除法计算显示，69/106 约为 65.09%。然而，系统却显示 66% 投给“否”，34% 投给“是”。请看图片：

 ![](https://global.discourse-cdn.com/meta/original/3X/9/0/908c0015a7b20679ee7888a142ea98d494f973cf.png)

最终结果是 72 票投给“否”，38 票投给“是”，投票现已关闭。72/110 约为 65.45%，系统也将其舍入为 66%，因此你可以在 [Tappara.co](https://tappara.co/t/saa-ottaa-talteen-eli-talteen-otetut/2745/60) 看到这一 bug 的实际表现。

我试图查看代码以找出导致 bug 的原因，但未能成功。我发现有一个名为 **evenRound** 的函数被调用，但当我搜索其源码时，没有找到。这只是一个猜测，也许该函数是将数字舍入到最近的 偶数 整数？

---

<div class="post-metadata">

### Author: ![zogstrip](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/zogstrip/32/512781_2.png) [@zogstrip](https://meta.discourse.org/u/zogstrip)
#### Post date: [2016 年11 月 2 日 11:24 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/2 "2016-11-02T11:24:54Z")

</div>

Not sure I understand what’s broken here. The poll will round the % so they add up to 100%.

> [@rizka](#):
>
> I tried to look at the code to find what causes the bug, but failed. I discovered that a function named evenRound is called, but when I seeked for its source, I didn’t find it.

> <https://github.com/discourse/discourse/blob/fc92166d5ffca6303d6fb6170923f7bb462267cd/plugins/poll/assets/javascripts/lib/even-round.js.es6>

---

<div class="post-metadata">

### Author: ![rizka](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rizka/32/79717_2.png) [@rizka](https://meta.discourse.org/u/rizka)
#### Post date: [2016 年11 月 2 日 12:45 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/3 "2016-11-02T12:45:23Z")

</div>

结果很糟糕，问题就出在这里。🙂

谢谢你的代码。我只是没找到它，这说明我在用 GitHub 方面真的很菜。代码是从 [Stack Overflow](http://stackoverflow.com/a/13484088) 上摘录的，原作者写道：

> 我不确定你需要多高的精度，但我建议的做法是：将小数部分总和向上取整得到的数值 n，对前 n 个数各加 1，其余的向下取整。比如这里 n 是 3，那么我就给前 3 项加 1，其余项向下取整。当然，这种方法不是超级精确，有些数字可能会在不该四舍五入的时候被舍入，但它效果还不错，而且最终结果总是 100%。

用这么粗暴的方法得到奇怪的结果也不足为奇。我建议我们要稍微复杂一点。[这篇帖子](http://stackoverflow.com/a/13483710) 在同一个话题下获得了 72 个赞成票，而代码来源的那篇帖子只有 1 个。

> 如果你不介意依赖原始的小数数据，有很多方法可以做到这一点。

> 第一种，也许也是最流行的方法是最大余数法（Largest Remainder Method）

> 其基本步骤是：

> 1. 将所有数字向下取整

> 1. 计算总和与 100 之间的差值

> 1. 按照小数部分从大到小的顺序，将差值分配给各项（每项加 1）

> …

我认为这种方法是最好的选择。它仍然非常简单，而且结果要好得多。当前的代码需要增加几行，以便告诉函数哪些数字应该向上取整。不过，还有一个问题需要考虑。来自同一话题的 [这篇帖子](http://stackoverflow.com/a/34959983) 指出：

> Varun Vohra 的高赞答案最小化了绝对误差之和，而且实现起来非常简单。但是，它无法处理一些边缘情况——比如对 24.25、23.25、27.25、25.25 进行四舍五入时，结果应该是什么？其中有一个数字需要向上取整而不是向下取整。

该帖子提出了各种方法来选择哪些数字向上取整，哪些向下取整，但你永远无法完全避免任意性。如果你追求完美，可以进一步阅读该帖子，但在这些罕见的特殊情况下，我也满足于使用这种方法。

> 你大概会任意选择列表中的第一个或最后一个。

希望这能帮到你。如果我先学习一些基本语法，我的技能可能足以自己进行改进。我现在不打算这么做，但如果有人在此之前没有处理这个问题，也许以后会做。

编辑：我把标题中的“broken”改成了“imprecise”，稍微优化了一下标题。这个话题也应该移到 #Contribute > Feature 频道，或者与之前的话题合并。

---

<div class="post-metadata">

### Author: ![zogstrip](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/zogstrip/32/512781_2.png) [@zogstrip](https://meta.discourse.org/u/zogstrip)
#### Post date: [2016 年11 月 2 日 13:49 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/4 "2016-11-02T13:49:07Z")

</div>

Feel free to submit a pull request to change the rounding algorithm 😉

---

<div class="post-metadata">

### Author: ![rizka](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rizka/32/79717_2.png) [@rizka](https://meta.discourse.org/u/rizka)
#### Post date: [2016 年11 月 3 日 09:22 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/5 "2016-11-03T09:22:33Z")

</div>

It was like classic exercises for beginning programmers. Here is a way to do it, but someone who has more experience and isn’t totally new to JavaScript might find some shortcuts.

[https://github.com/rizka10/discourse/pull/1/files](https://github.com/rizka10/discourse/pull/1/files)

---

<div class="post-metadata">

### Author: ![zogstrip](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/zogstrip/32/512781_2.png) [@zogstrip](https://meta.discourse.org/u/zogstrip)
#### Post date: [2016 年11 月 3 日 09:23 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/6 "2016-11-03T09:23:53Z")

</div>

Looks fine to me. Would you mind making it a PR so that I can merge it?

---

<div class="post-metadata">

### Author: ![rizka](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rizka/32/79717_2.png) [@rizka](https://meta.discourse.org/u/rizka)
#### Post date: [2016 年11 月 3 日 09:27 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/7 "2016-11-03T09:27:04Z")

</div>

I thought that was a pull request already… I’m as confused as always with Github. 😕  
I clicked some more green buttons now, maybe it does the trick?

---

<div class="post-metadata">

### Author: ![zogstrip](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/zogstrip/32/512781_2.png) [@zogstrip](https://meta.discourse.org/u/zogstrip)
#### Post date: [2016 年11 月 3 日 09:31 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/8 "2016-11-03T09:31:23Z")

</div>

If you want to create a PR from your code, you should go there: [https://github.com/discourse/discourse/compare/master...rizka10:master](https://github.com/discourse/discourse/compare/master...rizka10:master) 😉

---

<div class="post-metadata">

### Author: ![rizka](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rizka/32/79717_2.png) [@rizka](https://meta.discourse.org/u/rizka)
#### Post date: [2016 年11 月 3 日 09:36 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/9 "2016-11-03T09:36:14Z")

</div>

I think I’m getting it now. I ran into some Github tutorials online yesterday and I should really go through one to learn the basics.

---

<div class="post-metadata">

### Author: ![zogstrip](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/zogstrip/32/512781_2.png) [@zogstrip](https://meta.discourse.org/u/zogstrip)
#### Post date: [2016 年11 月 3 日 09:37 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/10 "2016-11-03T09:37:21Z")

</div>

Awesome. Before we can merge the code, we’ll need you to sign the CLA. I promise, this is the **last** step (also, you only have to sign it once ;))

---

<div class="post-metadata">

### Author: ![rizka](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rizka/32/79717_2.png) [@rizka](https://meta.discourse.org/u/rizka)
#### Post date: [2016 年11 月 3 日 09:40 UTC](https://meta.discourse.org/t/rounding-of-poll-percentages-is-imprecise/52319/11 "2016-11-03T09:40:51Z")

</div>

Thanks for all the help! I signed it now.
