我昨天写的这篇文章有点问题,我昨天只是查了几篇中文文章,想当然地写了本文,看到大家讨论以后,又仔细看了一下Wiki,英文滴,才明白“银行家规则”并不是简单“四舍六入五取偶”,而是只有在精确的 0.5 的情况下才会取偶,否则还是要四舍五入的。

Math.Round(2.5) = 2

Math.Round(2.5000000001) = 3

对于图书价格这个具体情境中,有不少书是几十五元整的,那么就会涉及到“取偶”的问题。但是这里要指出的是,这个和书价个位数的取值分布没有关系,而是和十位数的分布有关,因为个位数如果不是5,那么该怎么做就怎么做,用哪种方式取整都是一样的,也就和讨论无关了。而十位数则不然,假设所有个位数是5的书,只有35元和45元两种,那么按照四舍五入,就都向上取整了,这样就产生 bias了,而按照“取偶”的方式,则一个向上,一个向下,就消除了bias,更合理了。而是实际的书价,十位数的奇偶分布大致上是均匀的,因此用“取偶”的方式比一律向上取整的方式更合理一些。当然,这里要再强调一下,这里说的都只是针对个位是5的情况,和个位不是5的情况无关,而且书价是整数,不带小数。

补充说明:看到大家讨论得很热烈,推荐几篇相关资料,有高人可以选择一些翻译翻译:

近日在写“图灵社区3.0”的时候,才刚刚了解到一个以前没注意过的事儿:从小学就学过的“四舍五入”并不是想当然的那么简单。

在写程序的时候,四舍五入的算法固然可以自己来写,例如对于正数,某个数值加上 0.5 之后 Math.Floor,就可以了。但是既然我们使用的类库里提供了 Math.Round 函数,没有理由不用它。但是用过之后,你会发现结果并不是简单的四舍五入,例如:

Math.Round(2.5) = 2

Math.Round(3.5) = 4

这是为什么呢?Round 函数不能简单的翻译为四舍五入。具体来说,我们从小学习的“四舍五入”是不科学的。国际通行的是 Banker 舍入法(Banker 's rounding,银行家舍入)算法,顾名思义,就是银行在计算时使用的规则,即“四舍六入五取偶”。就是说小于 4 或大于 6 的该舍该入是没有争议的,而5处在正中间,采取的原则是:如果舍入位为5,则舍入后最后一位为偶数。事实上这也是 IEEE 规定的舍入标准。因此所有符合 IEEE 标准的语言都应该是采用这一规则的。这就解释了为什么 2.5 舍入以后以后是 2,而 3.5 舍入以后是 4。但是需要注意,只有精确的2.5舍入等于2,如果是 2.500001,舍入以后就是3了。

这个事实和图灵社区有什么关系呢?因为图灵要奖励读者,假如一本书电子书的定价是25元,而要反馈给购买该书读者等价于该书书价 10% 的银子,那么结果是 2.5 两银子,而图灵社区的银子最小单位就是 1 两,因此就必须要对这个数进行舍入。如果按照“四舍五入”的规则,应该给读者 3 两银子,如果按照“四舍六入五取偶”的规则,则应该给 2 两银子。

那么我们自然会想到,为什么说“四舍六入五取偶”比“四舍五入”则更科学呢?

假设有一个随机的自然数序列,然后其中每个数都加上0.5,形成如下的数列:

2.5, 4.5, 3.5, 7.5, 8.5, 9.5, 2.5

那么这个数列的平均值等于 38.5 / 7 = 5.5。

如果对每个数按照银行家规则舍入以后,平均值等于 38 / 7 = 5.4

如果按照四舍五入规则舍入以后,平均值就等于 42 / 7 = 6.0

可以看到,银行家规则更合理,也就是说四舍五入以后导致结果整体偏离了原来的平均值。

例如说,图灵一共卖出100本书,希望拿出收入的10%回馈读者,如果根据四舍五入的规则计算每个顾客的银子,然后加起来,就会超过10%了。而使用银行家规则则会更精确的接近10%的预算。

当然只能说银行家算法比四舍五入更科学,而不能说它就是绝对正确,而四舍五入就是错误的,因为这些结果都是基于统计数据产生的,前提就是这些数据符合随机性的要求。