ltl*_*lim 5 precision double vba variant
我正在使用Excel 2013.在以下代码片段中,VBA计算40 damage:
Dim attack As Variant, defense As Variant, damage As Long
attack = 152 * 0.784637
defense = 133 * 0.784637
damage = Int(0.5 * attack / defense * 70)
Run Code Online (Sandbox Code Playgroud)
如果数据类型更改为Double,则VBA计算39 damage:
Dim attack As Double, defense As Double, damage As Long
attack = 152 * 0.784637
defense = 133 * 0.784637
damage = Int(0.5 * attack / defense * 70)
Run Code Online (Sandbox Code Playgroud)
在调试器中,Variant/Double和Double值显示相同.但是,Variant/Double似乎更精确.
谁能解释这种行为?
tldr; 如果你需要比a更精确Double,不要使用a Double.
答案在于结果被强制转换成a Double的时间Variant.A Double是IEEE 754浮点数,根据IEEE规范,可逆性保证为15位有效数字.你的价值与这个限制调情:
0.5 * (152 * .784637) / (133 * .784637) * 70 = 39.99999999999997 (16 sig. digits)
Run Code Online (Sandbox Code Playgroud)
当被强制成双倍时,VBA将超过15位有效数字:
Debug.Print CDbl("39.99999999999997") '<--Prints 40
Run Code Online (Sandbox Code Playgroud)
实际上,您可以在VBE中观察此行为.输入或复制以下代码:
Dim x As Double
x = 39.99999999999997
Run Code Online (Sandbox Code Playgroud)
VBE通过将其转换为a来"自动更正"文字值Double,从而为您提供:
Dim x As Double
x = 40#
Run Code Online (Sandbox Code Playgroud)
好的,所以现在你可能会问这与2个表达式之间的区别有什么关系.VBA使用它可以使用的"最高阶"变量类型来评估数学表达式.
在您的第二个中Sub,您将所有变量声明为Double右侧,操作将按照高顺序进行计算Double,然后在作为参数传递之前将结果隐式转换为a .VariantInt()
在你的第一个Sub,你必须Variant声明,对隐式转换Variant不会传递到之前执行Int的最高等级的数学表达式- Variant,所以没有隐式转换进行传递结果之前Int()-将Variant仍然包含原始IEEE 754浮动.
每对文档的Int:
Int和Fix都删除数字的小数部分并返回结果整数值.
不执行舍入.顶级代码调用Int(39.99999999999997).底部代码调用Int(40)."答案"取决于您想要舍入的浮点错误级别.如果15个有效,则40是"正确"的答案.如果您想要将最多16个或更多有效数字放在地板上,那么39就是"正确"的答案.该解决方案是使用Round与指定的精度你正在寻找明确的水平.例如,如果您关心完整的15位数字:
Int(Round((0.5 * attack / defense * 70), 15))
Run Code Online (Sandbox Code Playgroud)
请记住,您在输入中的任何位置使用的最高精度是6位数,因此这将是一个逻辑舍入截止:
Int(Round((0.5 * attack / defense * 70), 6))
Run Code Online (Sandbox Code Playgroud)
如果你去掉计算伤害的两行上的 Int() 函数,那么它们最终会是相同的。您不应该使用 Int,因为这会产生错误行为,您应该使用 CLng,因为您要转换为 Long 变量,或者如果损坏是 Int,则应该使用 CInt。
Int 和 CInt 的行为不同。Int 总是向下舍入到下一个较小的整数 - 而 CInt 将使用银行舍入法向上或向下舍入。对于尾数为 0.5 的数字,您通常会看到这种行为。
至于变体和双精度的差异,如果您对第一个代码块的 MsgBox 执行 TypeName,您会发现分配值后的攻击和防御都已转换为双精度,尽管已声明为变体。
| 归档时间: |
|
| 查看次数: |
4078 次 |
| 最近记录: |