TL; DR; If you need higher precision than Double , do not use Double .
The answer lies in the time when the result is forcibly entered into Double from a Variant . A Double is an IEEE 754 floating point number, and 15 significant digits are guaranteed for the IEEE feedback specification. Your value flirts with this limit:
0.5 * (152 * .784637) / (133 * .784637) * 70 = 39.99999999999997 (16 sig. digits)
VBA will cover anything that does not exceed 15 significant digits when it is forcibly inserted into double:
Debug.Print CDbl("39.99999999999997") '<--Prints 40
In fact, you can watch this behavior in VBE. Enter or copy the following code:
Dim x As Double x = 39.99999999999997
VBE "automatically corrects" the literal value, dropping it to Double , which gives you:
Dim x As Double x = 40
Okay, so now you are probably asking what this means with the difference between the two expressions. VBA evaluates math expressions using the variable type "highest order" that it can.
In your second Sub , where you have the whole variable declared as Double on the right side, the operation is evaluated with a high order of Double , then the result is implicitly cast to Variant before being passed as a parameter to Int() .
In your first Sub , where you have Variant declarations, an implicit conversion in Variant not performed before going to Int - the highest order in the mathematical expression is Variant , therefore , an implicit conversion is not performed before passing the result to Int() - Variant by - still contains the untreated float IEEE 754.
Int documentation :
Both Int and Fix remove the fractional part of the number and return the final integer value.
Rounding is not performed. The top code calls Int(39.99999999999997) . The lower code calls Int(40) . The “answer” depends on what level of floating point error you want to round. If 15 works, then 40 is the “correct” answer. If you want to draw up to 16 or more significant digits, then 39 is the “correct” answer. The solution is to use Round and specify the level of accuracy you are looking for explicitly. For example, if you need the full 15 digits:
Int(Round((0.5 * attack / defense * 70), 15))
Keep in mind that the maximum accuracy you use anywhere in the inputs is 6 digits, so this will be a logical rounding:
Int(Round((0.5 * attack / defense * 70), 6))