用正数或无除数除以零(vba)

时间:2013-07-22 08:10:49

标签: excel vba divide-by-zero

我是Excel中的macros和vba的新手。目前,我正在为工作中的发票模板开发一个vba宏。 但是,我正在以零错误的方式运行,我无法追踪其原因。
有两个特定的代码行弹出,有时候......
第一部分:

    VATRMB = 0

第二部分:

    VATRMB = VATRMB + (0.0593 * (ActiveSheet.Range("I" & i).Value / (1 + 0.0593)))

Dim VATRMB存储如下:

        Dim startRow As Integer, endRow As Integer, VATRMB As Single, VATEUR As Single, VATUSD As Single, VATRMBCell As Range, VATEURCell As Range, VATUSDCell As Range

我看到这些线条的方式永远不应该抛出零除错误。在第一种情况下,没有任何除数,在第二种情况下,它总是积极的。
你有没有人知道为什么这可能会导致错误?它是否与sub被多次调用这一事实有关,重复使用相同的VATRMB Dim?它应该在每次调用sub后重置,对吧?或者它可以与我指定VATRMB为单身的事实有关吗?这适用于'小'(低于1,000,000)浮点数,对吗?

编辑:
1.添加用于调用Dim存储的确切行
2.这是使用的完整代码块,也许有助于澄清一两件事:

'Debug.Print Tab(10); ("Items will be searched in rows " & startRow & " thru " & endRow) 'Serves for debugging and testing
For i = startRow To endRow 'Loop the following code through all rows mentioned above
    If ActiveSheet.Range("B" & i).Find("Membership") Is Nothing Then 'If nothing is returned when searching for "Membership"; i.e. if the item in this row is not a membership payment
        If Not ActiveSheet.Range("H" & i).Find("RMB") Is Nothing Then 'If the value for this item is RMB denoted
            'Debug.Print Tab(20); "Item on Row " & i & " is RMB denoted, VAT = " & ((ActiveSheet.Range("I" & i).Value / (1 + 0.0593)) * 0.0593) 'Serves for debugging and testing
            VATRMB = VATRMB + (0.0593 * (ActiveSheet.Range("I" & i).Value / (1 + 0.0593))) 'Add row's VAT to VAT total
        End If
        If Not ActiveSheet.Range("H" & i).Find("EUR") Is Nothing Then 'If the value for this item is EUR denoted
            'Debug.Print Tab(20); "Item on Row " & i & " is EUR denoted, VAT = " & ((ActiveSheet.Range("I" & i).Value / (1 + 0.0593)) * 0.0593)  'Serves for debugging and testing
            'MsgBox VATEUR + 0.0593 * ActiveSheet.Range("I" & i).Value / (1 + 0.0593)
            VATEUR = VATEUR + (0.0593 * (ActiveSheet.Range("I" & i).Value / (1 + 0.0593))) 'Add row's VAT to VAT total
        End If
        If Not ActiveSheet.Range("H" & i).Find("USD") Is Nothing Then 'If the value for this item is USD denoted
            'Debug.Print Tab(20); "Item on Row " & i & " is USD denoted, VAT = " & ((ActiveSheet.Range("I" & i).Value / (1 + 0.0593)) * 0.0593)  'Serves for debugging and testing
            VATUSD = VATUSD + (0.0593 * (ActiveSheet.Range("I" & i).Value / (1 + 0.0593))) 'Add row's VAT to VAT total
        End If
    Else 'Else, i.e. if the row contains a membership payment, then essentially nothing happens
        'Debug.Print Tab(20); ("Item on Row " & i & " is a membership payment; no VAT paid.") 'Serves for debugging and testing
    End If
Next

所以我要做的是基本上遍历发票中的所有项目,从startRow到endRow,并通过解析'type'字符串(B列)来确定该项是否是会员付款。然后,根据是否为会员付款确定增值税,还要检查支付的货币。付款金额作为浮动数字存储在第I列中。

2 个答案:

答案 0 :(得分:0)

尝试将VATRMB = VATRMB +(0.0593 *(ActiveSheet.Range(“I”& i).Value /(1 + 0.0593)))行分成几部分并观察变量的内容。

    Dim VATRMB, i, rangeValue, dividor, divisionResult

    i = 1
    rangeValue = ActiveSheet.Range("I" & i).Value
    dividor = 1.0593
    divisionResult = rangeValue / dividor
    VATRMB = VATRMB + (0.0593 * divisionResult)  'Add row's VAT to VAT total

答案 1 :(得分:0)

不确定这是否是您问题的答案,因为您需要提供完整的工作簿等以确认。尽管如此,我们可以创建这种“应该是不可能的”情况,不仅可以实现Div0的100%再现性,而且几乎可以用于任何错误,例如:

VarX = 10  ' we can make this fail with Div0, Overflow or whatever

在我们的测试中,问题实际上并不是报告错误的“直接”或“显式”代码,而是错误发生在其他地方,而VBA以其无限的智慧恰好“报告”了错误。在奇怪的时间奇怪的方式(实际上它根本不应该报告某些错误,见下文)。

您的软件包是否涉及任何外部可执行文件,dll,addins'等?

如果是这样,那么这可能就是开始的地方。

如果没有,错误实际上可能直接或间接发生在您正在访问的范围内,但不一定在当前访问的单元格中。

这是一个通过在VBA中作为插件访问的DLL创建“Div0”的示例:假设您用另一种语言编写了一些代码,这里是Fortran(我们在任何地方使用Implicit None,并且所有内容都被正确声明等) :

Pure Subroutine FortDLL(x, U)
:
Real(DP), Intent(In)    :: x
Real(DP), Intent(Out)   :: U
:
Real(DP)                :: QQ
:
:
QQ = Log10(x) ! Notice this is not the return var and has nothing to do with anything on the VBA side (or so you would think)
:
U = 10.D0   ! Notice, this is the return var, and is a constant = 10.D0
:
End Subroutine FortDLL

以DLL的形式编译并以通常的方式访问。

然后假设你有一些VBA:

Function VBAFunc(x) as Variant
:
Call FortDLL(x, U)
:
Dim VarU as Variant
:
VarU = U   ; you can replace this with VarU = 10, or whatever, and will get same result/failure

现在,如果x< 0,然后DLL将废弃,因为没有为x<定义Log10。这将抛出一个Fortran运行时错误,并且根据你如何设置它,你可以让它抛出一个Div0,一个溢出(例如在Fortran一侧,MaxExponent为一个Double这里是1024,而在VBA上)取决于许多事物等等,它在308左右。)

现在即使QQ与VBA端没什么关系,当VBA代码执行FortDLL()时,它返回U = 10,它实际上正确地执行了该部分。

但是,DLL会抛出一个Div0(或者你想要创建的任何东西)错误,并且“错误消息”可以隐藏在返回Call FortDLL()中。

如果你没有使用DLL等,你可能会在你的“范围”或你的循环等其他地方发生类似的事情。

我们还没有对Dim as Currency“fix”的工作原理进行明确的测试,但我们猜测,因为Currency是一种非常特殊的Type(它实际上是一个至少有两个字段的结构化类型),“错误消息“可能埋没在其中一个”字段“中,并且可能不需要/与您正在使用的数字大小相关,并且通过”侥幸“(即一种”幸运的KLUDGE“)来避免崩溃。您可以通过为Double设置太大的数字并且需要货币类型的完整机器来测试这个。如果它是“幸运的KLUDGE”,那么有一天当你不在身边并且其他人正在使用你的代码时,他们进入数字需要完整的货币机制,然后它可能会崩溃,没有人会知道原因。

这是一个替代测试,假设您在像VarX = 10这样的行上崩溃,然后替换/修改如下:

:
On Error Resume Next
VarX = 10
VarX = 10
:

...如果这“有效”(即避免错误/崩溃),那么你的问题可能就像上面解释的那样(无论是“外部”还是“内部”)。在这种情况下,基本上,在第一次分配VarX时,“Div0问题”被视为VBA错误,因为设置了错误陷阱,“第一次”捕获并忽略“DLL侧错误”,并移动上。

......显然这只是一个测试,而不是解决方案。

这也可能是Excel / Win / Compiler(尤其是GCC,编译器VERSION,因为它们有一些非常古怪的东西/有时会有变化)依赖,因此可重复性和确切的行为可能会有所不同。