MOD函数在Excel VBA中专门使用长变量

Posted

技术标签:

【中文标题】MOD函数在Excel VBA中专门使用长变量【英文标题】:MOD Function Exclusively Uses Long Variables In Excel VBA 【发布时间】:2017-07-08 15:42:03 【问题描述】:

更新 解决后我正在清理这篇文章。总而言之,我正在为 excel 创建一个用户定义的公式,用于计算下一个最高的素数(=NextHighestPrimeNumber(100) 返回101)。当我开始试验时,我注意到这个公式会在大约 21 亿时出错。我认为它可能已连接到我的变量,所以我尝试了 DOUBLE,但仍然收到错误。

函数如下:

Function NextHighestPrimeNumber(StartingNumber As Double) As Variant
Dim CeilingTest As Long
Dim i As Long

If StartingNumber < 11 Then
            If StartingNumber > 6 Then
                NextHighestPrimeNumber = 11

            ElseIf StartingNumber > 4 Then
                NextHighestPrimeNumber = 7

            ElseIf StartingNumber > 2 Then
                NextHighestPrimeNumber = 5

            ElseIf StartingNumber > 0 Then
                NextHighestPrimeNumber = 3

            ElseIf StartingNumber = 0 Then
                NextHighestPrimeNumber = 1

            Else
                NextHighestPrimeNumber = "Pick A Positive Integer"

            End If

        Exit Function

Else

    'Create Array
    ReDim Prime_Array(0 To 4) As Double
    GoTo StartArrayPopulate
DoneWithStartingArray:

    If StartingNumber Mod 2 = 0 Then
        StartingNumber = StartingNumber - 1
    End If

NewNumber:
        StartingNumber = StartingNumber + 2
        CeilingTest = Int(VBA.Sqr(StartingNumber))


    'Array loop
    For i = LBound(Prime_Array) To UBound(Prime_Array)
        If Prime_Array(i) > CeilingTest Then
            NextHighestPrimeNumber = StartingNumber
            Exit Function
        ElseIf StartingNumber Mod Prime_Array(i) = 0 Then GoTo NewNumber

        End If
    Next i


    'Add new Array Value
ExpandDim:
    ReDim Preserve Prime_Array(UBound(Prime_Array) + 1)
    Prime_Array(UBound(Prime_Array)) = NextHighestPrimeNumber(Prime_Array(UBound(Prime_Array) - 1))

    'test if bigger than cieling
    If Prime_Array(UBound(Prime_Array)) > CeilingTest Then
        NextHighestPrimeNumber = StartingNumber
        Exit Function

    ElseIf StartingNumber Mod Prime_Array(UBound(Prime_Array)) = 0 Then GoTo NewNumber


    Else
        GoTo ExpandDim
    End If

End If


Exit Function

StartArrayPopulate:


Prime_Array(0) = 3
Prime_Array(1) = 5
Prime_Array(2) = 7
Prime_Array(3) = 11
Prime_Array(4) = 13


GoTo DoneWithStartingArray

End Function

【问题讨论】:

"LONG 变量,其范围应最大为 9,223,372,036,854,775,807" 这是在 VB.net 而不是 VBA 中。在后一种类型中,long 是 4 个字节。 显然您已经查阅了 VB.NET 参考。请咨询VBA reference。 VB datatypes size的可能重复 @GSerg 我现在是一个更有经验的overstacker(这是一个词吗??)。我认为这不能与您引用的内容重复,因为这最终是 MOD 函数专门使用数字作为 LONG 的方式。正如我的帖子在其原始状态中所说,当我切换到使用 DOUBLE 而不是 LONG 时它仍然失败,所以这并不是关于变量类型的问题,即使我最初做了不正确的引用。如果您删除降价和重复引用,我将不胜感激。没有像我在网站上的第一篇文章那样感到难过...谢谢。 【参考方案1】:

问题是因为 VBA MOD 函数 ALWAYS 将分子转换为 LONG 变量,即使它以前定义为 Double 或硬编码数字!

测试自己:

MsgBox (2147483647) mod 3 'Maximum Long Value

对比

MsgBox (2147483647 + 1) mod 3'Oh False!

我使用 INT 函数来复制 mod 计算 Numerator -(INT(Numerator /Denominator)*Denominator) 但还有很多其他创造性的方法可以避免。即使Evaluate带有excel MOD功能也能正常工作。

底线:我永远不会将 MOD 用于任何可能超过 20 亿的计算

自从我的第一篇文章以来,我已经大量清理了我的代码,并留下了注释掉的错误行,这些行抛出了带有 `zz failed code 标记的错误:

Function NextHighestPrimeNumber(StartingNumber As Double) As Variant
Dim CeilingTest As Long
Dim i As Long


If StartingNumber < 11 Then
            If StartingNumber > 6 Then
                NextHighestPrimeNumber = 11

            ElseIf StartingNumber > 4 Then
                NextHighestPrimeNumber = 7

            ElseIf StartingNumber > 2 Then
                NextHighestPrimeNumber = 5

            ElseIf StartingNumber > 0 Then
                NextHighestPrimeNumber = 3

            ElseIf StartingNumber = 0 Then
                NextHighestPrimeNumber = 1

            Else
                NextHighestPrimeNumber = "Pick A Positive Integer"

            End If

        Exit Function

Else

    'Create Array
    ReDim Prime_Array(0 To 4) As Double
    GoTo StartArrayPopulate
DoneWithStartingArray:

    'zz failed code: If StartingNumber Mod 2 = 0 Then
    If StartingNumber - (Int(StartingNumber / 2) * 2) = 0 Then
        StartingNumber = StartingNumber - 1
    End If

NewNumber:
        StartingNumber = StartingNumber + 2
        CeilingTest = INT(VBA.Sqr(StartingNumber))


    'Array loop
    For i = LBound(Prime_Array) To UBound(Prime_Array)
        If Prime_Array(i) > CeilingTest Then
            NextHighestPrimeNumber = StartingNumber
            Exit Function
        'zz failed code: ElseIf StartingNumber Mod Prime_Array(i) = 0 Then 
GoTo NewNumber
        ElseIf StartingNumber - (Int(StartingNumber / Prime_Array(i)) * Prime_Array(i)) = 0 Then GoTo NewNumber
        End If
    Next i


    'Add new Array Value
ExpandDim:
    ReDim Preserve Prime_Array(UBound(Prime_Array) + 1)
    Prime_Array(UBound(Prime_Array)) = NextHighestPrimeNumber(Prime_Array(UBound(Prime_Array) - 1))

    'test if bigger than ceiling
    If Prime_Array(UBound(Prime_Array)) > CeilingTest Then
        NextHighestPrimeNumber = StartingNumber
        Exit Function

    'zz failed code: ElseIf StartingNumber Mod Prime_Array(UBound(Prime_Array)) = 0 Then GoTo NewNumber
    ElseIf StartingNumber - (Int(StartingNumber / Prime_Array(UBound(Prime_Array))) * Prime_Array(UBound(Prime_Array))) = 0 Then GoTo NewNumber

    Else
        GoTo ExpandDim
    End If

End If


Exit Function

StartArrayPopulate:   
Prime_Array(0) = 3
Prime_Array(1) = 5
Prime_Array(2) = 7
Prime_Array(3) = 11
Prime_Array(4) = 13

GoTo DoneWithStartingArray

End Function

【讨论】:

对于 VBA7-64,这将显示 1Dim i As LongLong: i = 9123372036854775807: MsgBox i Mod 3 - Data Type Summary - MSDN VBA

以上是关于MOD函数在Excel VBA中专门使用长变量的主要内容,如果未能解决你的问题,请参考以下文章

Excel VBA 类属性返回公共长变量,但不是公共字符串变量

函数 MOD 上的 Excel 错误

具有变量名称的 Excel VBA 调用函数

excel vba中将公式转为文本或数值公式

在 Excel VBA 中使用长 Access SQL 查询

Excel,VBA中,如何判断变量是不是包含特定字符串