在.NET中四舍五入

同志们, 大胡子

我们都知道舍入是什么。 如果有人忘记了,那么四舍五入就是用近似值替换数字,该数字用较少的有效数字书写。 如果您即时询问某人,将6.5舍入为整数会发生什么,他会毫不犹豫地回答“ 7”。 我们从学校获悉,数字会四舍五入到最接近的整数,该整数的绝对值更大。 也就是说,如果在四舍五入的数字中分数部分等于或大于整个部分放电的一半,则我们将原始数字四舍五入到最接近的较大数字。

简单地说:
6,4 = 6 6,5 = 7 6,6 = 7 


因此,离开学校成为程序员之后,我们经常会期望我们强大的编程语言具有相同的行为。 完全忘记了在学校里我们被教过“数学舍入”,但是实际上舍入的类型更多。 仅在Wikipedia上, 您就可以挖掘多少舍入选项是0.5到最接近的整数:

  • 数学舍入
  • 随机取整
  • 交替舍入
  • 银行取整

我们都从学校学到了第一种类型的“数学取整”。 您可以在闲暇时阅读有关第二种和第三种的信息,今天我对它们并不感兴趣。

但是“银行四舍五入”已经很有趣。 “为什么?” -你问。 在子网中,我们经常使用Convert类,该类提供了许多用于将一种数据类型转换为另一种数据类型的方法(不要与强制类型转换混淆,下面将对其进行介绍)。 现在,事实证明,当通过Convert.ToInt32方法将浮点数( double,float,decimal )转换为整数int类型时 “ banking”舍入在幕后起作用。 默认情况下在这里使用它!

似乎对这个琐事的无知并不会在很大程度上影响您的工作,但是一旦您必须使用统计数据并根据大量各种记录和数字来计算指标,这件事就会横盘整理。 因为我们期望(由于无知)我们计算中的所有转换/舍入将根据“数学”舍入规则进行。 而且我们看起来像是新闸板上的公羊,其舍入结果为6.5 ,即6

看到这种情况的程序员的第一个想法是:“也许舍入是相反的方向,并且根据规则舍入到最小数?”,“也许我忘记了学校数学中的某些内容?”。 然后,他去了google,了解到他们没有忘记任何东西,并且某种暴民正在发生。 在这一步,懒惰的开发人员将确定这是Convert.ToInt32方法的标准行为,四舍五入到最小的整数,并为进一步的搜索打分。 并且他会认为,如果Convert.ToInt32(6,5) = 6 ,则通过类推Convert.ToInt32(7,5) = 7 。 但事实确实如此。 将来,此类开发人员将被质量检查部门的大量错误所吸引。

事实是,“银行”四舍五入有点棘手-将数字四舍五入到最接近的偶数,而不是最接近的整数取模。 对于在银行业务中应用这种情况,这种舍入方法应该更诚实-银行不会剥夺自己或客户,前提是存在偶数部分的操作与奇数部分的操作一样多。 但是对我来说-还不清楚:)因此, Convert.ToInt32(6.5)的结果为6 ,而Convert.ToInt32(7.5)的结果为8 ,而不是7 :)

如何使每个人都熟悉“数学”取整? 转换类方法没有其他舍入选项。 的确如此,因为此类主要用于舍入而不是类型转换。 出色的Math课程及其Round方法可助您一臂之力。 但是这里也要小心,因为默认情况下,此方法的作用与Convert.ToInt32()中的舍入相同-根据“银行”规则。 但是,可以使用第二个参数更改此行为,该参数是Round方法的一部分。 因此, Math.Round(someNumber, MidpointRounding.ToEven将为我们提供默认的“银行”舍入。 但是Math.Round(someNumber, MidpointRounding.AwayFromZero将根据“数学”舍入的通常规则工作。

顺便说一下, Convert.ToInt32()后台不使用System.Math.Round() 。 特别在github上挖掘此方法的实现 -根据残差考虑四舍五入:

 public static int ToInt32(double value) { if (value >= 0) { if (value < 2147483647.5) { int result = (int)value; double dif = value - result; if (dif > 0.5 || dif == 0.5 && (result & 1) != 0) result++; return result; } } else { if (value >= -2147483648.5) { int result = (int)value; double dif = value - result; if (dif < -0.5 || dif == -0.5 && (result & 1) != 0) result--; return result; } } throw new OverflowException(Environment.GetResourceString("Overflow_Int32")); } 

最后,关于类型转换的几句话:

 var number = 6.9; var intNumber = (int)number; 

在此示例中,我将浮点类型(在这种情况下为double )转换为整数int 。 因此,当转换为整数类型时,整个非整数部分都会被截断 。 因此,在此示例中,变量“ intNumber ”将包含数字6 。 这里没有舍入规则,只是舍去了小数点后的所有内容。 记住这一点!

相关链接:


PS感谢Maxim Yakushkin提请注意此隐性时刻。

PPS顺便说一句,在python中,默认情况下四舍五入的工作方式与“银行”基础相同。 也许您的语言也一样,请注意数字:)

Source: https://habr.com/ru/post/zh-CN462299/


All Articles