JP wrote:
Microsoft states: If either number1 or number2 is a floating-point value,
the floating-point remainder of the division is returned.
[....]
Floating-Point Imprecision
When you work with floating-point numbers, remember that they do not always have a precise representation in memory. This could lead to unexpected results from certain operations
[....]
So, IMO this proves that MOD should not be used when an argument is not an integer.
Amazing bit of (il)logic! You quote a statement that describes how to use MOD with non-integers [1], then you conclude "this proves" that MOD should not be used with non-integers.
I can only assume you are referring to the caveat about floating-point imprecision.
But if "that proves" that MOD should be used with non-integers, the same (il)logic applies to simple arithmetic operations like additiion, subtraction, division and multiplication.
For example: =(10.1 - 10 = 0.1) returns FALSE(!).
JP wrote:
=MOD(21,3;7,1) returns also 2^-49 or 1,77636E-15. As Dana stated, this is a -49th power of 2. Why does it always fails on this?
Because you are using constants? :-) :-)
Seriously, are you asking why the residual is "always" 2^-49?
It isn't. MOD(5631.93, 208.59) is about 1.99E-13, exactly 7*2^-45.
Perhaps more befuddling and insightful: in Excel 2010, MOD(279.4, 25.4) seems to return 25.4, even when formatted to display 15 significant digits.
A more careful comparison [2] -- MOD(279.4, 25.4)-25.4-0 -- reveals that the result is actually 25.4 - 7.1E-15, exactly 2^-47 less than the internal representation of 25.4.
The VBA functions below model 4 different ways to implement MOD. The algorithms are identical. The only difference is the precision of intermediate calculations. Hopefully, the comments are self-explanatory.
I want to emphasize that the VBA implementations below are merely models. I'm sure Excel uses a different computer language to implement MOD. The Excel implementation might behave differently for some MOD parameters.
Function vbmod80(n As Double, d As Double) As Double
' all 80-bit FP arithmetic
' n = 279.4 (279.399999999999,9772626324556767940521240234375)
' d = 25.4 (25.3999999999999,9857891452847979962825775146484375)
' vbmod80 ~= d (< d), = 25.3999999999999,914734871708787977695465087890625
' different from XL2003 MOD(n,d)
' same as XL2010 MOD(n,d)
vbmod80 = n - d * Int(n / d)
End Function
Function vbmod6480(n As Double, d As Double) As Double
' mixed 80-bit and 64-bit FP arithmetic
' n = 279.4 (279.399999999999,9772626324556767940521240234375)
' d = 25.4 (25.3999999999999,9857891452847979962825775146484375)
' vbmod6480 ~= 0 (< 0!) = -0.00000000000000710542735760100,185871124267578125
' same as XL2003 MOD(n,d)
' different from XL2010 MOD(n,d)
Dim t As Double
t = n / d
vbmod6480 = n - d * Int(t) ' 80-bit FP
End Function
Function vbmod8064(n As Double, d As Double) As Double
' mixed 80-bit and 64-bit FP arithmetic
' n = 279.4 (279.399999999999,9772626324556767940521240234375)
' d = 25.4 (25.3999999999999,9857891452847979962825775146484375)
' vbmod8064 ~= d (< d), = 25.3999999999999,772626324556767940521240234375
' different from XL2003, XL2010 MOD(n,d)
' different from vbmod80
Dim t As Double
t = d * Int(n / d) ' 80-bit FP
vbmod8064 = n - t
End Function
Function vbmod64(n As Double, d As Double) As Double
' all 64-bit FP arithmetic
' n = 279.4 (279.399999999999,9772626324556767940521240234375)
' d = 25.4 (25.3999999999999,9857891452847979962825775146484375)
' vbmod64 = 0
' different from XL2003, XL2010 MOD(n,d)
' different from vbmod6480
' same as XL2003, XL2010 formula: =n-d*INT(n/d)
Dim t As Double
t = n / d
t = Int(t)
t = d * t
vbmod64 = n - t
End Function
[1] Note that JP's excerpt is from a "man page" that explains how to use MOD with VB. It does not apply to VBA Mod, which uses only integral operands.
[2] The redundant -0 is needed to work around the dubious "close to zero" heuristic described in KB 78113 (click here), whereby Excel arbitrarily and inconsistently replaces an infinitesimal
result with zero.