C# 四舍五入
我有一个“科学应用”,在这个应用中,C# 四舍五入,c#,.net,C#,.net,我有一个“科学应用”,在这个应用中,单个值在显示在UI中之前应该四舍五入。根据,由于“精度损失”Math.Round(Double,Int32)方法有时会出现“意外”行为,例如将2.135舍入到2.13,而不是2.14 据我所知,这个问题与“银行家取整”无关(例如,请参阅) 在应用程序中,显然有人选择在取整(即Math.Round((Decimal)mySingle,2))之前显式地将Single转换为Decimal,以调用Math.Round(Decimal,Int32)重载来解决这个问题。除
单个
值在显示在UI中之前应该四舍五入。根据,由于“精度损失”Math.Round(Double,Int32)
方法有时会出现“意外”行为,例如将2.135舍入到2.13,而不是2.14
据我所知,这个问题与“银行家取整”无关(例如,请参阅)
在应用程序中,显然有人选择在取整(即Math.Round((Decimal)mySingle,2)
)之前显式地将Single
转换为Decimal
,以调用Math.Round(Decimal,Int32)
重载来解决这个问题。除了可能出现的二进制到十进制转换问题外,如果单个
值太小或太大而不适合十进制
类型,此“解决方案”还可能导致抛出溢出异常
如果转换失败,捕获这些错误以从Math.Round(Double,Int32)
返回结果,我认为这不是完美的解决方案。重写应用程序也不会一直使用Decimal
是否有一种或多或少“正确”的方法来处理这种情况,如果有,可能是什么?我刚刚查看了文档,似乎有一个枚举可以传递到Math.Round()
。如果您更改为Math.Round(Double,Int32,middpointrounding.AwayFromZero)
您应该会得到所需的结果
编辑:仅使用这些数字进行测试。更改了号码和
double abc = 2.335;
Console.WriteLine(Math.Round(abc, 2, System.MidpointRounding.AwayFromZero));
abc = 2.345;
Console.WriteLine(Math.Round(abc, 2, System.MidpointRounding.AwayFromZero));
abc = 2.335;
Console.WriteLine(Math.Round(abc, 2));
abc = 2.445;
Console.WriteLine(Math.Round(abc, 2));
得到了这些结果
2.34
2.35
2.34
2.44
编辑2:我用的是你给的原始数字,它正在崩溃。我认为使用AwayFromZero可以解决双舍入问题(我认为它只适用于银行家舍入),但事实并非如此。如果您确实需要从舍入中获得所需的精度,您必须创建自己的函数,通过转换为double或其他方法来提供所需的精度,但我已经寻找了一段时间,但没有找到任何结果,我会回来查看您是否找到了解决方案
double abc = 2.135;
Console.WriteLine(Math.Round(abc, 2, System.MidpointRounding.AwayFromZero));
abc = 2.145;
Console.WriteLine(Math.Round(abc, 2, System.MidpointRounding.AwayFromZero));
abc = 2.135;
Console.WriteLine(Math.Round(abc, 2));
abc = 2.145;
Console.WriteLine(Math.Round(abc, 2));
2.13
2.15
2.13
2.14
我认为您现有的解决方案(使用Math.Round的Decimal
版本)是正确的
潜在的问题是,您希望数字根据其以10为基数的表示形式进行舍入,但您将其存储为以2为基数的浮点数。所提供的2.135示例是基2表示与基10不完全匹配的边缘情况之一
要获得预期的舍入行为,必须将数字转换为以10为基数。最简单的方法就是您正在做的事情:临时将数字转换为一个十进制
,时间足够长,可以调用数学。舍入
,因为浮点以精度换取范围,所以十进制值2.135不能用二进制精确表示
[最接近的]二进制表示法类似于0.1348876953125
decimal,因此舍入是正确的(如果直观上不明显的话)
你应该读戈德伯格的论文,()
摘要。浮点运算被许多人认为是一门深奥的学科。这相当令人惊讶,因为浮点在计算机系统中无处不在:几乎每种语言都有浮点数据类型;从个人电脑到超级计算机都有浮点加速器;大多数编译器会不时被要求编译浮点算法;实际上,每个操作系统都必须响应浮点异常,例如溢出。本文介绍了一个有关浮点运算的教程,它对计算机系统的设计者有着直接的影响。它从浮点表示和舍入误差的背景开始,继续讨论IEEE浮点标准,并以计算机系统构建者如何更好地支持浮点的示例结束
请提供一个可运行的代码示例,其中2.135轮到2.13轮?小数的范围比单个小数的范围大,所以不应该有overflow@ScottChamberlain提供的MSDN链接包含此类代码。可能是,如果您可以仅为trunc转换它们,则可以使用Math。Truncate:@aochagavia I getSystem.OverflowException:值对于十进制而言太大或太小。在System.Decimal..ctor(单值)
。感谢您的贡献,但您可能没有花时间正确阅读我提供的链接。此外,我已经明确表示,我认为“银行取整”问题是一个不同的问题,并提供了足够的信息,您应该能够理解这意味着什么。对不起,我阅读了文档,它说,“在某些情况下,这一轮(双,中点取整)方法可能不会将中点值舍入为最接近的偶数整数”。我认为如果使用AwayFromZero,这将被忽略,但下面的示例表明,即使这样也不起作用。因此,您只能使用小数。但是当您将single转换为decimal时,不是也会发生同样的情况吗?值得注意的是,.NET decimal格式仍然没有存储真正的以10为基数的表示形式,因此如果在精度刻度的最末端重复添加/减去小数,您可能会遇到累加错误。它非常适合以有限的精度处理典型的base-10数学,但是,它将正确地复制“手动”计算,这些计算可以在base-10中以有限的小数进行。@Graham如果我理解正确,那么,是的,有一种舍入是在将一个单数转换为十进制时执行的。因此,2.134999999或其他任何东西被四舍五入到其十进制等价物2.135,然后被传递到Math.Round并转换为2.14。所以我不认为转换为十进制有帮助,因为在您的示例中,我希望2.1349四舍五入到2.13(s)