tldr;如果您需要比Double
更高的精度,請不要使用Double
。
答案在於結果從Variant
被強制爲Double
的時間。 A Double
是一個IEEE 754浮點數,並且根據IEEE規範的可逆性保證爲15位有效數字。你的價值與極限調情:
0.5 * (152 * .784637)/(133 * .784637) * 70 = 39.99999999999997 (16 sig. digits)
當它被強制轉換爲VBA將圓任何超出15顯著位雙:
Debug.Print CDbl("39.99999999999997") '<--Prints 40
事實上,你可以觀看此行爲VBE。鍵入或複製以下代碼:
Dim x As Double
x = 39.99999999999997
的VBE「自動校正」,由它強制轉換爲Double
,它給你的文字值:
Dim x As Double
x = 40#
好了,現在你可能會問這與2個表達式之間的區別有什麼關係。 VBA使用它可以的「最高階」變量類型來評估數學表達式。
在你把所有聲明爲Double
在右手側的可變的第二個Sub
,操作與Double
高階評估,然後在結果被隱式轉換爲Variant
視爲合格之前參數爲Int()
。
在你有Variant
聲明你的第一個Sub
,將隱式轉換爲Variant
不流通到Int
之前執行 - 在數學表達式中的最高階數Variant
,所以傳遞前進行沒有隱式轉換結果爲Int()
- Variant
仍包含原始IEEE 754浮點數。
每Int
的documentation:
兩個INT和修復除去數的小數部分,並返回 所得整數值。
不執行舍入。頂端代碼調用Int(39.99999999999997)
。底部代碼調用Int(40)
。 「答案」取決於你想要在什麼級別的浮點錯誤。如果15個工作,那麼40是「正確」的答案。如果您想要放置16位或更多的有效數字,那麼39是「正確的」答案。 解決方案將使用Round
並指定明確要查找的精度級別。例如,如果你關心的全部15位:
Int(Round((0.5 * attack/defense * 70), 15))
請記住,你在輸入的任何地方使用精度最高爲6位數字,所以這將是一個合乎邏輯的舍入截止:
Int(Round((0.5 * attack/defense * 70), 6))
改變'0.5'和'70'的順序,你會得到39:'Int(70 * attack/defense * 0.5)'。 – ThunderFrame