我做错了什么或者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
在我的舍入函数中使用它可以解决我的特定问题。
答案 0 :(得分:10)
模数或余数运算符将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