【问题标题】:Division by zero with positive or no divisor (vba)用正除数或无除数除以零 (vba)
【发布时间】:2013-07-22 08:10:48
【问题描述】:

我不熟悉 Excel 中的宏和 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 指定为 Single 的事实有关?这适用于“小”(低于 1,000,000)浮点数,对吗?

编辑:
1. 添加了调用 Dim storage 的确切行

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,并通过解析“类型”字符串(B 列)确定该项目是否为会员付款。然后,根据是否为会员付款确定增值税,还要检查支付的货币。付款金额以浮点数形式存储在 I 列中。

【问题讨论】:

  • 您能分享一下您用来调暗变量的确切行吗?有时人们在那个领域犯了错误,并没有对他们认为他们正在关注的东西进行调光。
  • 您能否举例说明您的工作表的 I 列中包含哪些值?我在 Excel03 和 Excel13 中的计算没有得到 DIV0 错误!
  • @matzone,不,它不能!
  • @ChrisSpicer 我将它添加到原始消息中,将前一部分替换为整行。
  • @AKDADEVIL 第 I 列包含该行上项目的单位成本,本质上是一个浮点数。

标签: excel vba divide-by-zero


【解决方案1】:

不确定这是否是您问题的答案,因为您需要提供完整的工作簿等来确认。尽管如此,我们可以创建这种类型的“这应该是不可能的”情况,不仅对于 Div0,而且对于几乎任何错误,都具有 100% 的可重复性,如下所示:

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

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

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

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

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

下面是一个通过在 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

现在虽然QQ与VBA端完全没有关系,但当VBA代码执行FortDLL()时,它返回U = 10,它实际上正确地完成了那部分。

但是,DLL 会引发 Div0(或任何您想要创建的)错误,并且“错误消息”是/可以隐藏在调用 FortDLL() 的返回中。

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

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

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    • 1970-01-01
    相关资源
    最近更新 更多