decimal.Round
方法使用舍入取整算法,这在大多数应用程序中并不常见。因此,我总是最终编写一个自定义函数来执行更自然的舍入算法: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;
}
有人知道这个框架设计决定背后的原因吗?
框架中是否有内置的Round-up-up-up算法?还是一些不受管理的Windows API?
对于初学者来说可能会产生误导,他们只需写
decimal.Round(2.5m, 0)
期望结果为3但得到2。#1 楼
可能是因为它是一种更好的算法。在执行许多舍入的过程中,您将平均得出所有.5的末尾均等地舍入。例如,如果添加一堆舍入的数字,则可以更好地估计实际结果。我会说,即使这不是某些人所期望的,也可能是更正确的选择。评论
假设您当然具有奇数和偶数输入的平面分布
– jk。
2010-1-22在13:04
+1可获得更好的算法,尽管Ostemar有实际答案(stackoverflow.com/questions/311696/…)
–伊恩·博伊德(Ian Boyd)
2011年9月9日14:01在
@Ian,我也给该答案+1。无论如何,我们可以将“接受的答案移动”,也许OP可以做到这一点。 “为什么”使用此方法的实际答案在页面的中间。尽管我非常喜欢销售代表提升,但我每周从这个答案中得到大约一次。
– Kibbee
2011年9月9日14:13
@Kibbee-感谢您提出我的答案。我想应该由OP来更改他认为合适的答案吗?
– Ostemar
2011-09-25 17:40
-1表示它是一个更好的算法。 -使用庄家四舍五入给定一个随机的数字样本,您最终将在偶数位置拥有比奇数位置更多的数字。 -只有在对这些数字取平均后,您才能再次获得与原始分布相似的点差。 -但是,例如,如果您将这些数据绘制在散点图中,则可能会看到人工分组。
–paul23
17年11月9日在6:07
#2 楼
为什么Banker的算法(也就是约半数到偶数)是一个很好的选择的其他答案是相当正确的。对于大多数合理的发行版,它没有负值或正值偏差的程度不如从零方法取整一半。但问题是为什么.NET使用Banker的实际取整作为默认值-答案是Microsoft遵循了IEEE 754标准。在MSDN中,Math.Round在“备注”下也提到了这一点。
还请注意,.NET通过提供
MidpointRounding
枚举来支持IEEE指定的替代方法。他们当然可以提供更多解决关系的替代方案,但他们选择仅满足IEEE标准。评论
那么,为什么IEEE 754遵循银行家四舍五入呢?这个(仍然很好)的答案刚刚过去了。
–汉克·霍尔特曼
13年3月14日在9:45
@HenkHolterman可能是由于其他答案中提到的内容(以及我总结的);它不会(过多)遭受负面或正面的偏见,因此,对于大多数分布和问题域而言,违约更为合理。
– Ostemar
13年4月12日在7:55
相关:Mathematica.SE:为什么四舍五入为整数?
–user247702
2014年4月2日在8:16
我认为这很有趣,因为IEEE 754是浮点数的标准,而十进制不是。也许遵循IEEE 754,所以使用相同的算法将Double舍入为Decimal。
–布兰登·巴克利
16-2-3在14:27
@BrandonBarkley十进制或十进制是浮点数,而IEEE 754确实包含十进制浮点数。
– Pablo H
18 Mar 23 '18 at 18:27
#3 楼
虽然我不能回答“为什么Microsoft的设计师为什么选择此默认值?”的问题,但我只想指出没有多余的功能。Math.Round
允许您指定MidpointRounding
:ToEven-当一个数字在两个其他数字的中间时,将四舍五入到最接近的偶数。
AwayFromZero-当一个数字在两个其他两个数字的中间时,则在四舍五入离零最近的数字。
评论
正如我在相关主题中提到的那样,请确保四舍五入是一致的-如果您有时在数据库中进行四舍五入,有时在.net中进行四舍五入,则您会遇到奇怪的1美分错误,这将使您花费数周的时间弄清楚。
–克里斯
09年3月6日在19:10
一个客户曾经向我支付了超过40,000美元,以追踪两个数字之间的0.11美元舍入误差,而这两个数字都略低于10亿美元; $ 0.11是由于大型机和SQL Server之间的第8位舍入错误不同。谈论完美主义者!
– E.J.布伦南
2010-1-22在13:10
@EJB-如果我处理的是十亿美元,我可能会是一个完美主义者;-)
–royse41
2010-09-10 10:52
@ E.J。 Brennan:花了4万美元弄清楚了吗?我一直看到这样的问题,四舍五入是原因1,双精度/浮点归一化是原因2,程序员错误#3-如果没有预定义的测试用例,则可以立即将#3设置为#1。顺便说一句,您能否请我与您的billionare客户联系,我想我也可以在他的系统中找到更多$ 40k的错误! :D
– Matthieu N.
2011年3月8日在2:30
@seanxe:或者您是否看过Office Space。认真地讲,每当您看到货币中的神秘细微误差时,准确地解决它们的发生方式之谜几乎总是一个好主意。您可能会决定不修复错误,但知道根本原因仍然有价值。我敢打赌,很多用钱工作的人都会高兴地注意到甚至很小的错误。
–布赖恩
2011年6月20日在16:52
#4 楼
小数多数用于赚钱;赚钱时,银行家的四舍五入很常见。或者你可以说。多数银行家都需要
十进制类型。因此,
“银行家四舍五入”
银行家四舍五入的优点是,如果您平均获得以下结果:
在添加“发票行”之前先对其进行四舍五入,
或将它们相加然后对总数进行四舍五入
在累加前进行舍入可以节省大量时间,而这要花在计算机之前。
(在英国,当我们去十进制银行时,十进制的硬币不能处理一半便士,但多年来仍然有一半便士的硬币,而且商店的价格通常以一半便士结尾-因此四舍五入)
评论
“小数多数用于赚钱” ...以及所有其他非整数的内容。
–约翰·泰瑞(John Tyree)
2013年12月13日22:30在
@JohnTyree,大多数情况下,如果不是整数,则使用double / float的情况并非如此。参见stackoverflow.com/questions/2545567/…
–伊恩·林格罗斯(Ian Ringrose)
2013年12月14日13:08
哇。我这可笑的错误。十进制,是的。小数,否。对于后代,我同意这里的原始观点。
–约翰·泰瑞(John Tyree)
13 Dec 16'2:59
银行家可能喜欢银行家的四舍五入,但簿记员可能不会喜欢它,他们说0.005的差异应四舍五入导致0.01的四舍五入,而不取决于它是奇数还是偶数。
– JustAMartin
16年6月17日在9:55
#5 楼
使用如下所示的Round函数的另一个重载:decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero)
它将输出3。如果使用
decimal.Round(2.5m, 0,MidpointRounding.ToEven)
您将获得银行家的四舍五入。
评论
这没有回答为什么选择“银行家四舍五入”作为默认值的问题。
–shortstuffsushi
17年4月13日在16:47
评论
舍入不是“更自然的”。大自然与它无关。这就是您在小学时学到的“四舍五入”概念。小学课程并不总是能完整呈现。@Rob这就是为什么它更自然的原因,即使它不正确
我不明白,@ Pacerier。我解释了为什么它不自然,而您说那实际上就是为什么它自然。我的论点如何与我的结论背道而驰,这与您的结论相反?您已经习惯的事物可能会感觉很自然,有时我们会比喻地说某事是“第二自然”,但这并不能使它们自然。
@Rob我说这很自然,因为感觉很自然。您知道有36个不同的对象,它们的自然名称相同吗?
大自然绝对是类比的,所以用错了这个词;但这是在学究。也许使用“通常”将是一个更好的词。.“人们通常进行的舍入是什么”> 0.5等于1.0