在Access中舍入小数位

时间:2017-09-21 16:28:49

标签: ms-access access-vba ms-access-2013

我正在使用Access来填充一些会计表单,并发现一个问题,它将.01添加到我的Excel工作表中。数据库设置为将数字除以3位小数。我遇到的问题是,除了分数后的数字是27.605,它将两个数字四舍五入到27.61,这两个数字组合时增加了一分钱。

如果小数点后3位为5或更多,我只需要对一个数字进行四舍五入,需要另一个数字向下舍入。这种方式当两个数字组合在一起时,它不会增加一分钱。我知道我描述的方式似乎很奇怪,但我们公司的形式因素附加费,它是电子表格中两倍的附加费。在电子表格的底部,它将两个附加费(一半)加在一起。

所以我在想

surcharge1 = equals half of the surcharge
surcharge2 = the other half of the surcharge

如果第3个小数位是5或更多圆形附加费1,最近的便士和圆形附加费2下降到最近的便士。关于如何正确使用此功能的任何想法?

2 个答案:

答案 0 :(得分:4)

您可以使用 Experts Exchange 中的 RoundUp RoundDown 函数here以及here > GitHub的。

您的用法是:

' Rounds Value up with count of decimals as specified with parameter NumDigitsAfterDecimals.
'
' Rounds to integer if NumDigitsAfterDecimals is zero.
'
' Optionally, rounds negative values away from zero.
'
' Uses CDec() for correcting bit errors of reals.
'
' Execution time is about 0.5µs for rounding to integer
' else about 1µs.
'
Public Function RoundUp( _
    ByVal Value As Variant, _
    Optional ByVal NumDigitsAfterDecimals As Long, _
    Optional ByVal RoundingAwayFromZero As Boolean) _
    As Variant

    Dim Scaling     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
        If NumDigitsAfterDecimals <> 0 Then
            Scaling = CDec(Base10 ^ NumDigitsAfterDecimals)
        Else
            Scaling = 1
        End If
        If Scaling = 0 Then
            ' A very large value for Digits has minimized scaling.
            ' Return Value as is.
            ReturnValue = Value
        ElseIf RoundingAwayFromZero = False Or Value > 0 Then
            ' Round numeric value up.
            If Scaling = 1 Then
                ' Integer rounding.
                ReturnValue = -Int(-Value)
            Else
                ' First try with conversion to Decimal to avoid bit errors for some reals like 32.675.
                On Error Resume Next
                ScaledValue = -Int(CDec(-Value) * Scaling)
                ReturnValue = ScaledValue / Scaling
                If Err.Number <> 0 Then
                    ' Decimal overflow.
                    ' Round Value without conversion to Decimal.
                    ScaledValue = -Int(-Value * Scaling)
                    ReturnValue = ScaledValue / Scaling
                End If
            End If
        Else
            ' Round absolute value up.
            If Scaling = 1 Then
                ' Integer rounding.
                ReturnValue = Int(Value)
            Else
                ' First try with conversion to Decimal to avoid bit errors for some reals like 32.675.
                On Error Resume Next
                ScaledValue = Int(CDec(Value) * Scaling)
                ReturnValue = ScaledValue / Scaling
                If Err.Number <> 0 Then
                    ' Decimal overflow.
                    ' Round Value without conversion to Decimal.
                    ScaledValue = Int(Value * Scaling)
                    ReturnValue = ScaledValue / Scaling
                End If
            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

    RoundUp = ReturnValue

End Function

这些是功能:

' Rounds Value down with count of decimals as specified with parameter NumDigitsAfterDecimals.
'
' Rounds to integer if NumDigitsAfterDecimals is zero.
'
' Optionally, rounds negative values towards zero.
'
' Uses CDec() for correcting bit errors of reals.
'
' Execution time is about 0.5µs for rounding to integer
' else about 1µs.
'
Public Function RoundDown( _
    ByVal Value As Variant, _
    Optional ByVal NumDigitsAfterDecimals As Long, _
    Optional ByVal RoundingToZero As Boolean) _
    As Variant

    Dim Scaling     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
        If NumDigitsAfterDecimals <> 0 Then
            Scaling = CDec(Base10 ^ NumDigitsAfterDecimals)
        Else
            Scaling = 1
        End If
        If Scaling = 0 Then
            ' A very large value for Digits has minimized scaling.
            ' Return Value as is.
            ReturnValue = Value
        ElseIf RoundingToZero = False Then
            ' Round numeric value down.
            If Scaling = 1 Then
                ' Integer rounding.
                ReturnValue = Int(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 = Int(CDec(Value) * Scaling)
                ReturnValue = ScaledValue / Scaling
                If Err.Number <> 0 Then
                    ' Decimal overflow.
                    ' Round Value without conversion to Decimal.
                    ScaledValue = Int(Value * Scaling)
                    ReturnValue = ScaledValue / Scaling
                End If
            End If
        Else
            ' Round absolute value down.
            If Scaling = 1 Then
                ' Integer rounding.
                ReturnValue = Fix(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 = Fix(CDec(Value) * Scaling)
                ReturnValue = ScaledValue / Scaling
                If Err.Number <> 0 Then
                    ' Decimal overflow.
                    ' Round Value with no conversion.
                    ScaledValue = Fix(Value * Scaling)
                    ReturnValue = ScaledValue / Scaling
                End If
            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

    RoundDown = ReturnValue

End Function

IntStream.range(0, 10)
  .map(x -> x * -1)
  .sorted()
  .map(Math::abs)
  .forEach(System.out::println);

请注意,VBA的原生 Round 是非常错误的。请参阅下载的测试模块。

答案 1 :(得分:2)

对于正确的舍入函数,你不会得到比古斯塔夫更好的答案,并且在只有两个组成值的情况下,免费的RoundDown和RoundUp函数就足够了。 (仅供参考,类似的功能通常在其他语言和编程库中命名为Floor和Ceiling。)

但是,当组成值与原始/期望值相加至关重要时,最好通过预期总和与所有其他舍入值之和的差来计算最后一个组成值。即使出现意外的舍入结果,这也可以保证正确的总和。即使使用有缺陷的VBA Round()函数,这种技术也可以避免1美分的错误。

surcharge1 = SomeRoundFunction(Total_Surcharge / 2.0)
surcharge2 = Total_Surcharge - surcharge1

这对于两个以上的组成值尤其重要,因为没有一组舍入函数可以正确舍入 3个或更多值以保证它们相加一些值。例如,我最近不得不通过(重新)计算折扣和税收来分割总交易金额。虽然我知道两者的百分比,但我需要将每个部分都计算为一分钱。折扣和税收都可以接受Penny错误,但是在任何四舍五入之后它们仍然需要加总。确保最终交易价值保持不变的唯一保证是首先计算和舍入税,然后计算和舍入折扣,最后通过从预期总数中减去部分总和来纠正便士错误。