Hi, All,
I'm intermediate for VB6. I want to get remainder from divided two doubles. I used ,
Dim a As Double, b As Double, result As Double
b = 8333.33
a = 58333.31
result = a - (b * Fix(a / b))
result is 8333.33; Why? Please help.
Printable View
Hi, All,
I'm intermediate for VB6. I want to get remainder from divided two doubles. I used ,
Dim a As Double, b As Double, result As Double
b = 8333.33
a = 58333.31
result = a - (b * Fix(a / b))
result is 8333.33; Why? Please help.
What's your actual question?Code:a=58333,31 b=8333,33
Fix(a / b) -> 6
b * 6 -> 49999,98
a - (49999,98) -> 8333,33
https://stackoverflow.com/questions/...dulo-operation
VB6:Code:The algorithm you want, to limit a floating point value between 0 and some modulus n:
Double fmod(Double value, Double modulus)
{
return value - Trunc(value/modulus)*modulus;
}
for example pi mod e (3.14159265358979 mod 2.718281828459045)
3.14159265358979 / 2.718281828459045
= 1.1557273497909217179
Trunc(1.1557273497909217179)
= 1
1.1557273497909217179 - 1
= 0.1557273497909217179
0.1557273497909217179 * e
= 0.1557273497909217179 * 2.718281828459045
= 0.42331082513074800
pi mod e = 0.42331082513074800
Code:Private Sub Form_Load()
Dim a As Double, b As Double, result As Double
b = 8333.33
a = 58333.31
result = a - (b * Fix(a / b))
Debug.Print result
Debug.Print fmod(a, b)
Debug.Print fmod(3.14159265358979, 2.71828182845905)
' -> 0.423310825130745
End Sub
Private Function fmod(value As Double, modulus As Double) As Double
fmod = value - Fix(value / modulus) * modulus
End Function
b = 8333.33
a = 58333.31
a/b =7 and no remain. So Fix(a / b) should be 7. But Fix(a / b)=6, is it correct?
That's the problem with floating point number respresentation, calculation and the internal storage in 64 bits.
Code:? 7 * 8333.33 - 58333.31
1.81898940354586E-12
Yep, a floatingpoint-mod-function needs to take these "small epsilons" into account:
HTHCode:Private Sub Form_Load()
Dim a#: a = 58333.31
Dim b#: b = 8333.33
Debug.Print a - b * Fix(a / b), fmod(a, b)
End Sub
Public Function fmod(ByVal Dividend#, ByVal Divisor#) As Double
fmod = Dividend - Fix(Dividend / Divisor) * Divisor
If Abs(fmod - Divisor) < Abs(Divisor * 0.000000001) Then fmod = 0
End Function
Olaf
Or use some small EPSILON value to fix the Fix function and to implemented comparison to zero with |A| < EPSION using Abs function like this:
cheers,Code:Option Explicit
Private Const EPSILON As Double = 0.0000001
Private Sub Form_Load()
Dim a#: a = 58333.31
Dim b#: b = -8333.33
Debug.Print "No remainder? -> "; Abs(fmod(a, b)) < EPSILON
Debug.Print Format$(fmod(a, b), "0.0000")
Debug.Print Format$(fmod(a, b), "0.00000000")
Debug.Print Format$(fmod(a, b), "0.000000000000")
End Sub
Private Function fmod(value As Double, modulus As Double) As Double
fmod = value - Fix(value / modulus + Sgn(value) * Sgn(modulus) * EPSILON) * modulus
End Function
</wqw>
Thanks for the indirect hint ...
(regarding the fmod-function I've posted in #6, which fails to return a zero with that negative Divisor-input).
Here's a correction:
Quite a bit longer than the first version (or yours) - but it now has less internal function-calls - and is therefore about 25% faster in native-compiled binaries... (though still about 10% slower in IDE or PCode).Code:Public Function fmod(ByVal Dividend#, ByVal Divisor#) As Double
Const EPS# = 0.00000001
If Divisor < 0 Then Divisor = -Divisor
If Dividend > 0 Then
fmod = Dividend - Int(Dividend / Divisor) * Divisor
If Abs(fmod - Divisor) < Divisor * EPS Then fmod = 0
Else
fmod = Dividend + Int(-Dividend / Divisor) * Divisor
If Abs(fmod + Divisor) < Divisor * EPS Then fmod = 0
End If
End Function
Olaf