Access 中的四舍五入小数位

Rounding decimal places in Access

我正在使用 Access 填充一些会计表格,发现它向我的 excel 工作表添加了 .01。数据库设置为将数字分成两半,保留 3 位小数。我遇到的问题是,假设除法后的数字是 27.605,它会将两个数字四舍五入为 27.61,这会在两个数字相加时增加一分钱。

如果小数点后第三位是 5 或更多,我只需要对一个数字进行四舍五入,而需要对另一个数字进行四舍五入。这样,当两个数字相加时,它不会增加一分钱。我知道我所描述的方式似乎很奇怪,但我们公司的形式因素附加费并且在电子表格中两次是附加费的一半。在电子表格的底部,它将两个附加费(一半)总额相加。

所以我在想

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

如果小数点后第 3 位为 5 位或更多,附加费 1 向上舍入到最接近的美分,附加费2 向下舍入到最接近的美分。关于如何正确实现此功能的任何想法?

您可以使用 RoundUpRoundDown 函数 here at Experts Exchange and hereGitHub

您的用法是:

Value = 27.605 
Value1 = RoundUp(Value, 2)    ' 27.61 
Value2 = RoundDown(Value, 2)  ' 27.6

这些是函数:

' 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

请注意,VBA 的原生 Round 有很多问题。查看下载的测试模块。

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

但是,当成分值总和等于 original/expected 值很关键时,最好通过预期总数与所有其他四舍五入的总和之差来计算最后一个成分值值。即使四舍五入产生意外结果,这也将保证正确的总和。即使使用有缺陷的 VBA Round() 函数,这种技术也可以避免 1 美分的错误。

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

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