有没有办法在.NET做“正确的”算术舍入? / C#
-
22-09-2019 - |
题
我想圆一个数字,它的小数点后第一位,并考虑不同MidpointRounding选项,这似乎运作良好。一个问题出现时,虽然这一数字有sunsequent小数会算术影响四舍五入。
的示例:
使用0.1
,0.11..0.19
和0.141..0.44
它的工作原理:
Math.Round(0.1, 1) == 0.1
Math.Round(0.11, 1) == 0.1
Math.Round(0.14, 1) == 0.1
Math.Round(0.15, 1) == 0.2
Math.Round(0.141, 1) == 0.1
但是,随着0.141..0.149
它总是返回0.1
,虽然0.146..0.149
应该轮0.2
:
Math.Round(0.145, 1, MidpointRounding.AwayFromZero) == 0.1
Math.Round(0.146, 1, MidpointRounding.AwayFromZero) == 0.1
Math.Round(0.146, 1, MidpointRounding.ToEven) == 0.1
Math.Round(0.146M, 1, MidpointRounding.ToEven) == 0.1M
Math.Round(0.146M, 1, MidpointRounding.AwayFromZero) == 0.1M
我试图想出解决此问题,和它运作良好,这种情况下的功能,但当然glamorously如果你试图轮即0.144449
到它的第一个十进制数(这应该是0.2
,但结果失败0.1
。)(不工作与Math.Round()要么。)
private double "round"(double value, int digit)
{
// basically the old "add 0.5, then truncate to integer" trick
double fix = 0.5D/( Math.Pow(10D, digit+1) )*( value >= 0 ? 1D : -1D );
double fixedValue = value + fix;
// 'truncate to integer' - shift left, round, shift right
return Math.Round(fixedValue * Math.Pow(10D, digit)) / Math.Pow(10D, digit);
}
我假定一个解决办法是枚举所有数字,找到第一个值大于4,然后舍入,否则向下舍入。问题1:这似乎白痴,问题2:我不知道如何枚举数字无需乘法和subtractios的极大数
。长话短说:什么是做到这一点的最好办法
解决方案
Math.Round()
正确行为。
当您要执行标准中点取整,你永远需要超越1十进制数字超出你在哪里取整到。如果你是四舍五入到最接近的十分之一,那么你永远需要超越第二位小数点后。
与中点的舍入的想法是的一半的在两者之间数字应围捕和半应该向下取整。因此,对于0.1和0.2之间的数字,其中一半应四舍五入到0.1,一半应一轮0.2。这两个数字之间的中点是0.15,所以这是对围捕的门槛。 0.146小于0.15,因此它必须向下舍入为0.1。
Midpoint
0.10 0.15 0.20
|----------------|----|---------------------|
0.146
<---- Rounds Down
其他提示
我不明白你正试图在这里完成的。 0.149四舍五入到小数点后一位的就是 0.1,而不是0.2
舍入不是一个反复的过程,则圆只有一次。
所以0.146舍入到1个十进制数字的就是 0.1。
您不这样做:
0.146 --> 0.15
0.15 --> 0.2
您只能这样做:
0.146 --> 0.1
,否则以下:
0.14444444444444446
也将圆至0.2,但它不和不应该。
不要试图化合物舍入“错误”。这是你想要做什么。
0.146的应的一轮下跌到0.1,如果你打算到小数点后一位。
通过再次四舍五入到0.15,再.2你只是引入更多的舍入误差,而不是更少。