Why does .NET use banker's rounding as default?
根据文献的方法,使用一个decimal.Round全面均衡算法的最普通的应用是困难的。所以我总是最终编写自定义函数做了更多的自然循环式算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public static decimal RoundHalfUp(this decimal d, int decimals)
{
if (decimals < 0)
{
throw new ArgumentException("The decimals must be non-negative",
"decimals");
}
decimal multiplier = (decimal)Math.Pow(10, decimals);
decimal number = d * multiplier;
if (decimal.Truncate(number) < number)
{
number += 0.5m;
}
return decimal.Round(number) / multiplier;
} |
没有人知道原因在本框架的设计决策?
有没有任何内置的全面实施半升到框架的算法?或也许一些非托管的Windows API?
对于成本,它可以是简单的初学者写的decimal.Round(2.5m, 0)as a result,但希望获得3而不是2。
- >我希望是72.5,但结果是72.4,我不会。你是说你要把2.444444444444444449调到3?(如果小数点后四舍五入到零位)
- 取舍不是"更自然的",自然与此无关。当你在小学学习"四舍五入"的概念时,它只是你在中学学到的。小学的课程并不总是描绘出一幅完整的画面。
- @Rob这就是为什么它更自然,即使它不正确
- 我不明白,@pacerier。我解释了为什么它不是自然的,你说这就是为什么它是自然的。我的论点如何与我的结论相悖?这与你的观点相反?你已经习惯的东西可能会感觉自然,有时我们比喻地说有些东西是"第二天性",但这并不能使它们自然。
- @Rob我是说这是自然的,因为感觉很自然。你知道有36个不同的物体有相同的变量名,自然对吗?
- 自然是绝对相似的,所以它是一个错误的词,但这是学究。也许"惯用"是个更好的词。"人们通常做的四舍五入是什么">0.5变为1.0
- 顺便说一句,有趣的是,当转换为字符串时舍入一个双精度数时,使用的是零舍入(即0.5.ToString("0") =="1")。我认为通常当你旋转时,你会在屏幕上显示数值。所以这真的很有趣。
- @是的,我也觉得很奇怪。这是自.NET开始以来一直存在的一般"不一致"。还有一个不知道的例子:如果d = 9.825m是Decimal(确切地说是可代表的),那么decimal.Round(d, 2)和Math.Round(d, 2)之类的东西给9.82,而d.ToString("F2")、d.ToString("N2")和d.ToString("0.00")这样的格式给"9.83"(decimal分隔符字符,取决于当前线程的区域性)。不友好。
- @Jeppestiginelsen我唯一能想到的理由是,当对屏幕上显示的值进行取整时,您不需要银行家取整的统计效益。远离零取整的"自然感觉"可能是更好的选择。因此到字符串的转换是这样的。当必须在其他计算中使用舍入值时,银行家舍入的统计效益是有用的。正是那种你会使用Math.Round的情况。
- 偏离主题:银行家的四舍五入应该是公正的,这在理论上是公正的。但实际上,(在金融界)有更多的偶数,这使得这一问题存在争议。
- @乔文:很多价格都以9结尾,这是真的,但这并不会产生太大的偏差。例如,价格可以是含税或不含税等。当然,更大的价格往往不是9元到最后一位(在最后5位之前)。总而言之,在我参与过的所有金融应用程序中,银行家的取整都非常有效。
- @Pacerier:在银行应用程序中,在绝大多数情况下,您只需要进行大量的求和。每次求和都可能给结果增加误差。为了使误差最小化,所采用的算法不应偏袒,也就是说,它有时应该向上取整,有时应该向下取整。什么让你的大脑感觉自然并不重要。真正重要的是特定用例或需求所施加的需求。如果银行家回合可以说是解决这个问题的最佳方案…好。。。使用它是很自然的!
- @顺便说一下,金融应用程序(我的意思是,由熟练的开发人员编写)采用定点算法,而不是浮点算法。采用定点算法,计算精度高,无舍入误差。
另一个答案是,为什么银行家的算法(也就是半圆形到偶数圆形)是一个很好的选择,这是非常正确的。在最合理的分布情况下,它不受负偏压或正偏压的影响。
但问题是,为什么.NET使用Banker的实际舍入作为默认值——答案是微软已经遵循了IEEE754标准。这也在msdn for math.round的备注中提到。
还请注意,.NET通过提供MidpointRounding枚举支持IEEE指定的替代方法。当然,他们可以为解决关系提供更多的选择,但他们选择只满足IEEE标准。
- 那么,为什么IEEE754遵循银行家的四舍五入?这个(仍然很好)答案只是转瞬即逝。
- @Henkholterman可能是由于其他答案中提到的内容(如我所总结的);它不会受到(太多)负面或正面偏见的影响,因此对于大多数分布和问题领域而言,这会导致更合理的违约。
- 相关:mathematica.se:为什么舍入为偶数?
- 我认为这很有趣,因为IEEE754是浮点数的标准,十进制数不是。也许它遵循IEEE754,所以使用相同的算法将双精度取整为十进制。
- @brandonbarkley十进制或十进制是一个浮点数,IEEE754也包括十进制浮点数。
- 有趣。我没有真正思考过十进制数字是如何呈现和存储的。
- @亨霍尔特曼:或者有人会认为微软已经过关了。
可能是因为它是一个更好的算法。在执行的许多舍入过程中,您将平均得出所有.5的最终舍入相等。这可以更好地估计实际结果,例如,添加一组四舍五入的数字。我会说,尽管这不是一些人所期望的,但这可能是更正确的做法。
- 假设你有一个奇数和偶数输入的平面分布
- +1为了更好的算法,尽管Ostemar有实际的答案(stackoverflow.com/questions/311696/&hellip;)
- @伊恩,我也给出答案+1。不管怎样,我们可以移动"已接受的答案",也许操作员可以这样做。它使用此方法的"为什么"的实际答案是页面的一半。虽然我很喜欢这个答案,但是我每周都会得到一次。
- @kibbee-谢谢你推我的答案。我想应该由行动党来改变他认为合适的答案了吧?
- -1表示这是一个更好的算法。-如果使用银行家的四舍五入随机抽取一个数字样本,那么在偶数位置的数字将多于奇数位置的数字。-只有在对这些数字进行平均后,才能再次得到与原始分布类似的分布。-但是,例如,如果您将这些数据绘制在散点图中,您可能会看到人工分组。
- 对于未来的访问者,dango的回答(stackoverflow.com/a/7360463/1204599)很好地补充了这一点,并提供了一个很好的例子,演示了选项MidpointRounding.ToEven如何产生更准确的结果。
虽然我不能回答"为什么微软的设计师选择这个作为默认值?",我只是想指出一个额外的函数是不必要的。
Math.Round允许您指定MidpointRounding:
- 当一个数介于两个数之间时,它会四舍五入到最接近的偶数。
- A从零开始-当一个数字介于两个数字之间时,它会四舍五入到离零最近的数字。
- 正如我在相关的线程中提到的,确保在四舍五入中保持一致——如果有时在数据库中进行四舍五入,有时在.NET中进行四舍五入,则会出现奇怪的一分错误,需要花费数周的时间才能解决。
- 有一次,一个客户支付了我4万多美元来跟踪两个数字之间的0.11美元的舍入误差,这两个数字都不到10亿美元;0.11美元是由于大型机和SQL Server之间的第8位舍入误差的差异造成的。说说完美主义者!
- @EJB-如果我处理10亿美元,我可能是一个完美主义者;-)
- @布伦南:你花了4万美元才弄明白?我一直看到这样的问题,舍入是原因1,双/浮点标准化是原因2,如果没有预先定义的测试用例,程序员错误3 3可以立即设置为1。顺便说一句,你能让我和你的亿万富翁客户联系一下吗?我想我也能在他的系统中找到4万美元的漏洞!D
- @或者如果你看到过办公空间。说真的,每当你看到钱中有神秘的、微小的不准确之处,解决它们究竟是如何发生的这个谜几乎总是一个好主意。您可能会决定不修复bug,但知道根本原因仍然有价值。我敢打赌,许多用钱工作的人都很乐意注意到即使是微小的错误。
- +1用于列出.NET中已有的其他舍入方法。
- "为什么微软的设计师选择这个作为默认值?"他们没有,是IEEE。请看Ostemar的回答:stackoverflow.com/a/6562018/385844(抱歉,我的措辞很难听,但如果我为我遇到的每一个认为"微软在他们的取整程序中有一个错误"的开发人员提供了一分钱…)
- @马修:也许他的小时工资是8万美元。:)
- @E.J.Brennan这通常不是关于完美主义,而是关于(愚蠢的,愚蠢的)法律。我也不得不做类似的事情(舍入"错误"与"美分"相关的卡支付,但不是现金支付)。这个错误一年大约是0.1美元,但是花了将近一个月的时间才得到正确的"修复"(客户偶尔还会打电话给我们,因为他害怕报告没有显示四舍五入的值,我必须再次解释为什么这是正确的,逻辑和法律)。当一个税务官员出现这样一个0.1美元的错误时,罚款是多少?高达10万美元。大多数法律都很荒谬:)
小数主要用于货币;银行家在处理货币时通常使用四舍五入。或者你可以说。
It is mostly bankers that need the
decimal type; therefore it does
"banker’s rounding"
银行家四舍五入的优点是,如果您:
- 将一组"发票行"舍入,然后再将它们相加,
- 或者把它们加起来,然后把总数四舍五入
加起来之前的四舍五入节省了计算机前几天的大量工作。
(在我们去英国的时候,十进制的银行不会处理半便士的问题,但多年来,仍有半便士的硬币,商店的价格通常以半便士结束——所以有很多四舍五入法)
- "小数主要用于钱"…以及其他不是整数的东西。
- @johntyree,当double/float不是整数时,大多数情况下都不是这样。参见stackoverflow.com/questions/2545567/&hellip;
- 真的。我犯了荒谬的错误。是的。小数,不是。对于子孙后代,我同意最初的观点。
- 银行家们可能喜欢银行家们的四舍五入,但簿记员们可能不喜欢,他们说0.005的差额应该四舍五入到0.01,这不取决于是奇数还是偶数。
使用类似以下的另一个循环函数重载:
1
| decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero) |
它将输出3。如果你使用
1
| decimal.Round(2.5m, 0,MidpointRounding.ToEven) |
你会得到银行的四舍五入。
- 这并不能回答为什么银行的四舍五入被选为违约的问题。