Mod双打

时间:2014-05-08 18:39:07

标签: vba ms-access double modulus

我做错了什么或者VBA Mod操作符实际上不能使用双打这样的浮点值吗?

所以我总是假设VBA Mod操作符可以基于VB documentation使用Doubles,但是在试图弄清楚为什么我的舍入功能不起作用时,我发现一些意外的Mod行为。

这是我的代码:

Public Function RoundUp(num As Double, Optional nearest As Double = 1)
    RoundUp = ((num \ nearest) - ((num Mod nearest) > 0)) * nearest
End Function

RoundUp(12.34)返回12而不是13,所以我深入挖掘并发现:

12.5 Mod 1返回0,返回类型为Long,而我的预期为0.5,类型为Double。


结论

作为@ckuhn203 points out in his answer,根据VBA规范,

  

模数或余数运算符将number1除以number2   (将浮点数舍入为整数)并仅返回   剩余的结果。

  

通常,结果的数据类型是Byte,Byte变体,Integer,   包含Long的整数变量,Long或Variant,无论如何   结果是否是整数。任何小数部分   截断。

出于我的目的,我需要一个浮点模,所以我决定使用以下内容:

Public Function FMod(a As Double, b As Double) As Double
    FMod = a - Fix(a / b) * b

    'http://en.wikipedia.org/wiki/Machine_epsilon
    'Unfortunately, this function can only be accurate when `a / b` is outside [-2.22E-16,+2.22E-16]
    'Without this correction, FMod(.66, .06) = 5.55111512312578E-17 when it should be 0
    If FMod >= -2 ^ -52 And FMod <= 2 ^ -52 Then '+/- 2.22E-16
        FMod = 0
    End If
End Function

以下是一些例子:

FMod(12.5, 1) = 0.5 FMod(5.3, 2) = 1.3 FMod(18.5, 4.2) = 1.7

在我的舍入函数中使用它可以解决我的特定问题。

4 个答案:

答案 0 :(得分:10)

根据VB6/VBA documentation

  

模数或余数运算符将number1除以number2   (将浮点数舍入为整数)并仅返回   剩余的结果。例如,在下面的表达式中,A   (结果)等于5. A = 19 Mod 6.7通常,结果的数据类型是   字节,字节变体,整数,整数变体,长整型或变体   包含一个Long,无论结果是否是一个整体   数。任何小数部分都被截断。但是,如果有的话   表达式为Null,结果为Null。任何空表达式都是   被视为0。

请记住,mod返回分区的余数任何整数 mod 1 = 0.

debug.print 12 mod 1 
'12/1 = 12 r 0

这里真正的罪魁祸首是vba在执行模数之前将双精度截断(向下舍入)整数

?13 mod 10
 '==>3 
?12.5 mod 10
 '==>2 

debug.print 12.5 mod 1
'vba truncates 12.5 to 12
debug.print 12 mod 1
'==> 0

答案 1 :(得分:4)

我相信Mod运算符只用long类型计算。您提供的链接适用于VB.Net,它与您在MSAccess中使用的VBA不同。

VBA中的运算符似乎接受双精度类型,但只是在内部将其转换为long。

该测试结果为1.

9 Mod 4.5

该测试结果为0。

8 Mod 4.5

答案 2 :(得分:0)

作为替代方案,您可以对值做一些简单的数学运算。要获得两位十进制精度,只需将输入值乘以100,然后将结果除以100。

result = (123.45*100 Mod 1*100)/100
result = (12345 Mod 100)/100
result = 0.45

我参加聚会很晚,但是以防万一,这个答案仍然对某人有用。

答案 3 :(得分:0)

在VBS中尝试此操作

Option Explicit

Call Main()

Sub Main()

    WScript.Echo CStr(Is_Rest_Of_Divide_Equal_To_Zero(506.25, 1.5625))

End Sub


Function Is_Rest_Of_Divide_Equal_To_Zero(Divident, Divisor)

    Dim Result
    Dim DivideResult

    If Divident > Divisor Then
        DivideResult = Round(Divident/Divisor, 0)
        If (DivideResult * Divisor) > Divident Then
            Result = False
        ElseIf (DivideResult * Divisor) = Divident Then
            Result = True
        ElseIf (DivideResult * Divisor) < Divident Then
            Result = False
        End If
    ElseIf Divident = Divisor Then
        Result = True
    ElseIf Divident < Divisor Then
        Result = False
    End If

    Is_Rest_Of_Divide_Equal_To_Zero = Result

End Function