如何围绕MS Access,VBA

什么是在VBA访问中最好的方法?

我目前的方法利用Excel方法

Excel.WorksheetFunction.Round(... 

但是我正在寻找一种不依赖于Excel的方法。

要小心,VBA Round函数使用Banker的四舍五入,在0.5到偶数的位置,如下所示:

 Round (12.55, 1) would return 12.6 (rounds up) Round (12.65, 1) would return 12.6 (rounds down) Round (12.75, 1) would return 12.8 (rounds up) 

而Excel工作表函数轮,总是四舍五入。

我已经做了一些testing,它看起来像.5舍入(对称舍入)也用于单元格格式,也用于列宽舍入(当使用通用数字格式时)。 “显示的精确度”标志本身并不会做任何舍入,只是使用单元格格式的舍入结果。

我尝试从VBA中的微软实现SymArith函数为我的四舍五入,但发现修复时有一个错误,当你尝试给它一个数字,如58.55; 58.5而不是58.6的结果。 然后,我终于发现,你可以使用Excel Worksheet Roundfunction,如下所示:

Application.Round(58.55,1)

这将允许您在VBA中进行正常舍入,尽pipe它可能不如某些自定义函数那么快。 我意识到这个问题已经到了完整的一步,但是为了完整起见,我想把它包括进来。

在接受的答案上扩大一点:

“Round函数执行的是圆的,而不是圆的到大的。”
– 微软

格式总是四舍五入。

  Debug.Print Round(19.955, 2) 'Answer: 19.95 Debug.Print Format(19.955, "#.00") 'Answer: 19.96 

您使用浮点数字时ACC 2000:四舍五入错误: http : //support.microsoft.com/kb/210423

ACC 2000:如何四舍五入一个数字向上或向下所需的增量: http : //support.microsoft.com/kb/209996

回合函数: http : //msdn2.microsoft.com/en-us/library/se6f2zfx.aspx

如何实现自定义舍入程序: http : //support.microsoft.com/kb/196652

在瑞士,特别是在保险行业,我们不得不使用几个舍入规则,这取决于它是否会带来利益等等。

我目前使用的function

 Function roundit(value As Double, precision As Double) As Double roundit = Int(value / precision + 0.5) * precision End Function 

这似乎工作正常

Int和Fix是有用的四舍五入function,它给你一个数字的整数部分。

Int总是舍入 – Int(3.5)= 3,Int(-3.5)= -4

修复总是趋于零 – 修复(3.5)= 3,修复(-3.5)= -3

还有强制函数,特别是CInt和CLng,试图强制一个整数或长整数(整数在-32,768和32,767之间,长整数在-2,147,483,648和2,147,483,647之间)。 (3.5)= 4,Cint(3.49)= 3,CInt(-3.5)= -4等等,从零到四舍五入。

 1 place = INT(number x 10 + .5)/10 3 places = INT(number x 1000 + .5)/1000 

等等。你会发现这样的解决scheme显然比使用Excel函数要快得多,因为VBA似乎在不同的内存空间中运行。

例如, If A > B Then MaxAB = A Else MaxAB = B大约比使用ExcelWorksheetFunction.Max快40倍

如果你正在讨论四舍五入到一个整数值(而不是四舍五入到小数点后n位),那么总是有老派的方式:

 return int(var + 0.5) 

(你也可以把这个工作做成n个小数位,但是开始有点乱)

Lance已经提到了VBA实现中的inheritance四舍五入bug 。 所以我需要一个真正的四舍五入function在VB6应用程序。 这是我正在使用的一个。 它是基于我在网上find的一个,如评论中所示。

 ' ----------------------------------------------------------------------------- ' RoundPenny ' ' Description: ' rounds currency amount to nearest penny ' ' Arguments: ' strCurrency - string representation of currency value ' ' Dependencies: ' ' Notes: ' based on RoundNear found here: ' http://advisor.com/doc/08884 ' ' History: ' 04/14/2005 - WSR : created ' Function RoundPenny(ByVal strCurrency As String) As Currency Dim mnyDollars As Variant Dim decCents As Variant Dim decRight As Variant Dim lngDecPos As Long 1 On Error GoTo RoundPenny_Error ' find decimal point 2 lngDecPos = InStr(1, strCurrency, ".") ' if there is a decimal point 3 If lngDecPos > 0 Then ' take everything before decimal as dollars 4 mnyDollars = CCur(Mid(strCurrency, 1, lngDecPos - 1)) ' get amount after decimal point and multiply by 100 so cents is before decimal point 5 decRight = CDec(CDec(Mid(strCurrency, lngDecPos)) / 0.01) ' get cents by getting integer portion 6 decCents = Int(decRight) ' get leftover 7 decRight = CDec(decRight - decCents) ' if leftover is equal to or above round threshold 8 If decRight >= 0.5 Then 9 RoundPenny = mnyDollars + ((decCents + 1) * 0.01) ' if leftover is less than round threshold 10 Else 11 RoundPenny = mnyDollars + (decCents * 0.01) 12 End If ' if there is no decimal point 13 Else ' return it 14 RoundPenny = CCur(strCurrency) 15 End If 16 Exit Function RoundPenny_Error: 17 Select Case Err.Number Case 6 18 Err.Raise vbObjectError + 334, c_strComponent & ".RoundPenny", "Number '" & strCurrency & "' is too big to represent as a currency value." 19 Case Else 20 DisplayError c_strComponent, "RoundPenny" 21 End Select End Function ' ----------------------------------------------------------------------------- 

不幸的是,可以执行四舍五入的VBA的本地函数缺失,有限,不准确或错误,并且每个函数都只处理一个舍入方法。 好处是它们很快,而且在某些情况下可能很重要。

但是,通常精度是强制性的,而且随着计算机速度的加快,稍微慢一点的处理就不会被注意到,事实上不是处理单个值。 下面链接中的所有function运行约1μs。

完整的函数集 – 对于所有常见的舍入方法,VBA的所有数据types,任何值,不返回意外值 – 可以在这里find:

将值上下四舍五入,或者加上有效数字(EE)

或在这里:

将值上下四舍五入,或重复数字(CodePlex)

仅在GitHub上进行编码:

VBA.Round

他们涵盖了正常的舍入方法:

  • 向下舍入,可以select将负值舍入为零

  • 向上取整,可以select从零开始舍入负值

  • 四舍五入,或者从零或甚至(银行家的舍入)

  • 四舍五入到有效数字

前三个函数接受所有的数字数据types,而最后三个函数分别存在三种 – Currency,Decimal和Double。

它们都接受一个指定的小数位数 – 包括一个负数,可以舍入到几十,几百等等。Variant作为返回types的那些将返回Null作为不可理解的input

还包括用于testing和validation的testing模块。

一个例子就是 – 普通的四舍五入。 请仔细研究细节内容和CDec用于避免误码的方式。

 ' Common constants. ' Public Const Base10 As Double = 10 ' Rounds Value by 4/5 with count of decimals as specified with parameter NumDigitsAfterDecimals. ' ' Rounds to integer if NumDigitsAfterDecimals is zero. ' ' Rounds correctly Value until max/min value limited by a Scaling of 10 ' raised to the power of (the number of decimals). ' ' Uses CDec() for correcting bit errors of reals. ' ' Execution time is about 1µs. ' Public Function RoundMid( _ ByVal Value As Variant, _ Optional ByVal NumDigitsAfterDecimals As Long, _ Optional ByVal MidwayRoundingToEven As Boolean) _ As Variant Dim Scaling As Variant Dim Half As Variant Dim ScaledValue As Variant Dim ReturnValue As Variant ' Only round if Value is numeric and ReturnValue can be different from zero. If Not IsNumeric(Value) Then ' Nothing to do. ReturnValue = Null ElseIf Value = 0 Then ' Nothing to round. ' Return Value as is. ReturnValue = Value Else Scaling = CDec(Base10 ^ NumDigitsAfterDecimals) If Scaling = 0 Then ' A very large value for Digits has minimized scaling. ' Return Value as is. ReturnValue = Value ElseIf MidwayRoundingToEven Then ' Banker's rounding. If Scaling = 1 Then ReturnValue = Round(Value) Else ' First try with conversion to Decimal to avoid bit errors for some reals like 32.675. ' Very large values for NumDigitsAfterDecimals can cause an out-of-range error ' when dividing. On Error Resume Next ScaledValue = Round(CDec(Value) * Scaling) ReturnValue = ScaledValue / Scaling If Err.Number <> 0 Then ' Decimal overflow. ' Round Value without conversion to Decimal. ReturnValue = Round(Value * Scaling) / Scaling End If End If Else ' Standard 4/5 rounding. ' Very large values for NumDigitsAfterDecimals can cause an out-of-range error ' when dividing. On Error Resume Next Half = CDec(0.5) If Value > 0 Then ScaledValue = Int(CDec(Value) * Scaling + Half) Else ScaledValue = -Int(-CDec(Value) * Scaling + Half) End If ReturnValue = ScaledValue / Scaling If Err.Number <> 0 Then ' Decimal overflow. ' Round Value without conversion to Decimal. Half = CDbl(0.5) If Value > 0 Then ScaledValue = Int(Value * Scaling + Half) Else ScaledValue = -Int(-Value * Scaling + Half) End If ReturnValue = ScaledValue / Scaling End If End If If Err.Number <> 0 Then ' Rounding failed because values are near one of the boundaries of type Double. ' Return value as is. ReturnValue = Value End If End If RoundMid = ReturnValue End Function 

在Access 2003中总是可以使用下面的整数:

 BillWt = IIf([Weight]-Int([Weight])=0,[Weight],Int([Weight])+1) 

例如:

  • [重量] = 5.33; Int([Weight])= 5; 所以5.33-5 = 0.33(<> 0),所以答案是BillWt = 5 + 1 = 6。
  • [Weight] = 6.000,Int([Weight])= 6,所以6.000-6 = 0,所以答案是BillWt = 6。
 VBA.Round(1.23342, 2) // will return 1.23 

为了解决一分钱一分钱的问题,我们创build了一个用户定义的函数。

 Function PennySplitR(amount As Double, Optional splitRange As Variant, Optional index As Integer = 0, Optional n As Integer = 0, Optional flip As Boolean = False) As Double ' This Excel function takes either a range or an index to calculate how to "evenly" split up dollar amounts ' when each split amount must be in pennies. The amounts might vary by a penny but the total of all the ' splits will add up to the input amount. ' Splits a dollar amount up either over a range or by index ' Example for passing a range: set range $I$18:$K$21 to =PennySplitR($E$15,$I$18:$K$21) where $E$15 is the amount and $I$18:$K$21 is the range ' it is intended that the element calling this function will be in the range ' or to use an index and total items instead of a range: =PennySplitR($E$15,,index,N) ' The flip argument is to swap rows and columns in calculating the index for the element in the range. ' Thanks to: http://stackoverflow.com/questions/5559279/excel-cell-from-which-a-function-is-called for the application.caller.row hint. Dim evenSplit As Double, spCols As Integer, spRows As Integer If (index = 0 Or n = 0) Then spRows = splitRange.Rows.count spCols = splitRange.Columns.count n = spCols * spRows If (flip = False) Then index = (Application.Caller.Row - splitRange.Cells.Row) * spCols + Application.Caller.Column - splitRange.Cells.Column + 1 Else index = (Application.Caller.Column - splitRange.Cells.Column) * spRows + Application.Caller.Row - splitRange.Cells.Row + 1 End If End If If (n < 1) Then PennySplitR = 0 Return Else evenSplit = amount / n If (index = 1) Then PennySplitR = Round(evenSplit, 2) Else PennySplitR = Round(evenSplit * index, 2) - Round(evenSplit * (index - 1), 2) End If End If End Function 

我使用以下简单的函数来圈定我们的货币,就像我们公司总是围绕一样。

 Function RoundUp(Number As Variant) RoundUp = Int(-100 * Number) / -100 If Round(Number, 2) = Number Then RoundUp = Number End Function 

但总是会有2位小数,也可能是错误。

即使是负值,也会收敛(-1.011为-1.01,1.011为1.02)

所以要提供更多的四舍五入的选项(或否定的),你可以使用这个函数:

 Function RoundUp(Number As Variant, Optional RoundDownIfNegative As Boolean = False) On Error GoTo err If Number = 0 Then err: RoundUp = 0 ElseIf RoundDownIfNegative And Number < 0 Then RoundUp = -1 * Int(-100 * (-1 * Number)) / -100 Else RoundUp = Int(-100 * Number) / -100 End If If Round(Number, 2) = Number Then RoundUp = Number End Function 

(在模块中使用,如果不明显)