VBA中最大可能的十进制值是多少?
Posted
技术标签:
【中文标题】VBA中最大可能的十进制值是多少?【英文标题】:What is the largest possible decimal value in VBA? 【发布时间】:2019-02-05 12:45:21 【问题描述】:我一直在尝试在vba 中创建类似于DEC_MAX
常量的东西。
问题是,有点棘手,因为没有Decimal
data-type!
最接近有效小数的是 CDec()
定义的函数:
返回作为表达式结果的十进制数据值 强制转换为十进制
所以很自然,我认为任何潜在的溢出值都会被强制到最大可实现的Decimal
。我尝试从MSDN Documentation 插入最大十进制vb.net 值
但请注意,这是真的,因为尝试这样做会导致溢出:
那么如何计算最接近十进制最大值的近似值呢?我尝试了这个“computer-bricking”丑陋的代码循环:
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,而不用过多关注计算。
所以,
-
如何计算它?
我们可以传递给
CDec()
函数的最大可能表达式是多少?
【问题讨论】:
bettersolutions.com/vba/functions/cdec-function.htm Does this help? 一个 IDE 错误? - 我输入Debug.Print CDec(79228162514264337593543950335)
,当我点击离开该行时IDE会自动将其转换为Debug.Print CDec(7.92281625142643E+28)
(双文字,因为没有十进制文字ofc)如果我按F5运行我得到一个溢出 i> 错误(不正确)。如果我回到该行,删除并重新输入 CDec
然后 F5 再次运行它可以工作并打印 79228162514264300000000000000
【参考方案1】:
我能弄清楚如何做到这一点的唯一方法是完全绕过 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
【讨论】:
Declare PtrSafe
可能是 Private
;-) ..也可能需要用 #If VBA7
包装,如果代码为 VBA6,则另一种 Declare
(不是 PtrSafe
)需要在旧版本中正确编译和运行。在#Win64
下,可以使用LongLong
来稍微简化逻辑。不过可能不值得。
@MathieuGuindon 已修复。 ;-)【参考方案2】:
我不确定问题是什么,因为提出了很多意图/问题:
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() 函数的最大可能表达式是多少?
如上
【讨论】:
以上是关于VBA中最大可能的十进制值是多少?的主要内容,如果未能解决你的问题,请参考以下文章