我正在尝试将一个数字舍入到它的第一个小数位,考虑到不同的MidpointRounding选项,这似乎运作良好。但是,当该数字具有随后的小数位数时会出现问题,这些小数位数会在算术上影响舍入。
一个例子:
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
:
0.144449
我尝试提出一个解决这个问题的函数,它适用于这种情况,但当然如果你试图将0.2
舍入到它的第一个十进制数字(应该是0.1
,但结果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);
}
。)(这也不适用于Math.Round()。)
{{1}}
我假设一个解决方案是枚举所有数字,找到大于4的第一个值然后向上舍入,否则向下舍入。问题1:这似乎是愚蠢的,问题2:我不知道如何在没有大量乘法和减法的情况下枚举数字。
长话短说:最好的方法是什么?
答案 0 :(得分:20)
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
答案 1 :(得分:15)
我不知道你想要在这里完成什么。 0.149舍入到一个小数位是 0.1,而不是0.2
答案 2 :(得分:6)
舍入不是一个迭代过程,只能绕一次。
所以0.146四舍五入到1位十进制数 0.1。
你不这样做:
0.146 --> 0.15
0.15 --> 0.2
你只这样做:
0.146 --> 0.1
否则,以下内容:
0.14444444444444446
也会变为0.2,但它不会,也不应该。
答案 3 :(得分:5)
不要尝试复合舍入'错误'。这就是你要做的。
.146 应该向下舍入到.1,如果你要到一个小数位。
首先将其四舍五入为.15,然后再将其四舍五入为.2,您只是引入了更多的舍入误差,而不是更少。