VBA中最大的十进制值是多少?

时间:2018-08-30 14:17:36

标签: excel vba exception error-handling limit

我一直试图在中创建类似于DEC_MAX常量的内容。


问题是,这有点棘手,因为没有Decimal数据类型
最接近有效十进制的是CDec()函数,其定义如下:

  

返回作为表达式结果的十进制数据值   强制转换为十进制

因此,我自然而然地认为,任何潜在的过度价值都将被强制达到最大可实现的Decimal。我尝试从插入最大十进制MSDN Documentation

这是正确的,因为这样做会导致溢出:

enter image description here

那么在这里如何去计算十进制最大值的最接近的近似值呢?我尝试了这个“计算机崩溃” 丑陋的代码循环:

Private Sub brick_my_Excel()
  On Error Resume Next
  x = 79228162514264337593543950335 'let's let it auto-coerce i guess
  Do 
     Debug.Print(x)
     x = x - 1
  Loop
End Sub

但这完全阻止了溢出,以几乎像字符串的方式打印x,而无需过多地关注计算。

所以

  1. 如何计算呢?
  2. 我们可以传递给CDec()函数的最大表达式是什么?

2 个答案:

答案 0 :(得分:8)

我能弄清楚如何做到这一点的唯一方法是完全绕过VBA并“构建”内存中的最大值。 The DECIMAL structure是16个字节,定义为:

typedef struct tagDEC {
  USHORT    wReserved;
  BYTE      scale;
  BYTE      sign;
  ULONG     Hi32;
  ULONGLONG Lo64;
} DECIMAL;

由于您无法在VBA中显式声明Decimal,因此CDec(0)将为您提供正确的Variant类型的内容。符号和小数位与12个字节的值无关,因此只需设置该内存区域中的所有位,便会得到最大值(最大小数位为0):

#If VBA7 Then
    Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias _
        "RtlMoveMemory" (Destination As LongPtr, Source As Any, _
        ByVal length As Long)
#Else
    Private Declare Sub CopyMemory Lib "kernel32" Alias _
        "RtlMoveMemory" (Destination As Long, Source As Any, _
        ByVal length As Long)
#End If

Private Const VT_DECIMAL As Integer = &HE
Private Const BIT_MASK As Long = &HFFFFFFFF
Private Const DATA_OFFSET = 4
Private Const SIZEOF_LONG = 4

Public Function MaxDecimal() As Variant
    'Get a decimal to work with.
    Dim dec As Variant
    dec = CDec(0)

    Dim vtype As Integer
    'First 2 bytes are the VARENUM.
    CopyMemory ByVal VarPtr(vtype), ByVal VarPtr(dec), LenB(vtype)

    'Make sure the VARENUM is a VT_DECIMAL.
    If vtype = VT_DECIMAL Then
        'Fill the top 12 bytes of it's data area with truthy bits
        CopyMemory ByVal VarPtr(dec) + DATA_OFFSET, BIT_MASK, SIZEOF_LONG
        CopyMemory ByVal VarPtr(dec) + DATA_OFFSET + SIZEOF_LONG, BIT_MASK, SIZEOF_LONG
        CopyMemory ByVal VarPtr(dec) + DATA_OFFSET + SIZEOF_LONG * 2, BIT_MASK, SIZEOF_LONG
    End If

    MaxDecimal = dec
End Function

请注意,这显然不会为您带来一个Const的好处,但确实会为您提供正确的最大值:

Public Sub Test()
    MsgBox MaxDecimal
End Sub

Maximum Decimal Value

答案 1 :(得分:1)

我不确定问题是什么,因为提出了很多意图/问题:

  

VBA中最大的十进制值是多少?

如您所知:79228162514264337593543950335

  

我一直试图在vba中创建类似于DEC_MAX常量的东西。

您不会将Variant转化为常量,但是String可能对您有用吗?

  

如何计算呢?

赞:

Public Const MAX_DEC_STRING = "79228162514264337593543950335"

Public Function MAX_DEC() As Variant
    MAX_DEC = CDec(MAX_DEC_STRING)
End Function

Sub test()
    Dim v As Variant, x As Variant
    v = MAX_DEC
    x = CDec("79228162514264337593543950334")   '7922816251426433759354395033

   MsgBox v - x
End Sub
  

我们可以传递给CDec()函数的最大可能表达式是什么?

同上