今天修改以前的Access程序时,发现函数round()不能实现四舍五入,当舍去位为5时,有时会进位,有时又直接舍去,机会各占50%。
在VBA立即窗口中测试:
?(round(18605/10,0)*10)
18600
?(round(18615/10,0)*10)
18620
?round(1.25,1)
1.2
?round(1.35,1)
1.4
这样与要实现的功能不相符,很苦恼,查了一下,才知道原因!
原来VBA采用的是“银行家舍入法”,据说大部分的编程软件都使用的是这种方法,也算是一种国际标准。
所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法。其规则是:当舍去位的数值小于5时,直接舍去该位;当舍去位的数值大于等于6时,在舍去该位的同时向前位进一;当舍去位的数值等于5时,如果前位数值为奇,则在舍去该位的同时向前位进一,如果前位数值为偶,则直接舍去该位。
简单的说,就是:四舍六入,五判断,五前奇进偶不进(五前是奇则进,五前为偶不进)。
这样一看就很明白了,果然是各占50%。
原因明白了,如何解决以实现真正的四舍五入呢!
搜了一下,找到两种方法,整理如下:
1,先加一个很小的数,然后再round取整。这个方法还是不错的!
?(round(18605/10+0.000001,0)*10)
18610
?(round(18615/10+0.000001,0)*10)
18620
?round(1.25+0.000001,1)
1.3
?round(1.15+0.000001,1)
1.2
2,自定义函数,代替round函数。如下:
Function RoundUp(pInput As Double, pPos As Integer) As Double
^代替Round()函数,实现真正的四舍五入
^注:round()函数采用的是银行家舍入法,四舍六入,五判断,五前奇进偶不进Dim pStr As String
If pInput <> 0 Then
pStr = "#." & String(pPos, "#")
RoundUp = Format(pInput, pStr)
Else
RoundUp = 0
End IfEnd Function
但很奇怪的是,excel中采用的并不是这种方式,而是真正的四舍五入,可能这个不是编程用的缘故。。。。。
PS:
关于银行家舍入法,又查到一个解释,上面的不太全面。
银行家舍入法即“四舍六入法”,可以概括为:“四舍六入五考虑,五后非零就进一,五后皆零看奇偶,五前为偶应舍去,五前为奇要进一”。
这个口诀更全面~~
其中“五后非零就进一,五后皆零看奇偶”正是第一种解决方法的原理了~~
忽然想到delphi中也遇到过这样的问题,但当时未细究。测试一下,果然如此,看来编程软件确实都是采用的这种方式。
也测试了一下,第一种方法同样适用于Delphi~~
【版權聲明】
本文爲原創,遵循CC 4.0 BY-SA版權協議!轉載時請附上原文鏈接及本聲明。
原文鏈接:https://tdlib.com/am.php?t=dSSdoIHsdisJ Tag: VB技巧 Access技巧 Delphi技巧 TTTBLOG