Page 1 of 1
Mod function returning the same value as the Divisor
Posted: Thu Oct 29, 2020 10:54 pm
by ricardo_sdl
Take the following code:
Code: Select all
CurrentFrame.f = 3.87199997901917
Elapsed.f = 0.01600000075996
CurrentFrame = Mod(CurrentFrame + Elapsed * 8, 4)
If CurrentFrame >= 4.0
Debug "instead is 4 or more"
Else
Debug "CurrentFrame should be zero"
EndIf
I expected CurrentFrame to be 0(zero) after the call to Mod, this is probably floating point tricking me again!

Re: Mod function returning the same value as the Divisor
Posted: Thu Oct 29, 2020 11:05 pm
by Little John
When using one additional line, it works as expected.
Code: Select all
CurrentFrame.f = 3.87199997901917
Elapsed.f = 0.01600000075996
CurrentFrame = CurrentFrame + Elapsed * 8
CurrentFrame = Mod(CurrentFrame, 4.0)
If CurrentFrame >= 4.0
Debug "instead is 4 or more"
Else
Debug "CurrentFrame is zero"
EndIf
Re: Mod function returning the same value as the Divisor
Posted: Fri Oct 30, 2020 1:05 am
by Tawbie
Hi ricardo_sdl,
I think the issue is the limited resolution of floats. It works as expected if you use doubles.
Code: Select all
CurrentFrame.d = 3.87199997901917
Elapsed.d = 0.01600000075996
CurrentFrame = Mod(CurrentFrame + Elapsed * 8, 4)
If CurrentFrame >= 4.0
Debug "instead is 4 or more"
Else
Debug "CurrentFrame should be zero"
EndIf
Re: Mod function returning the same value as the Divisor
Posted: Fri Oct 30, 2020 2:14 am
by normeus
@twabie, you are right about using a double for larger precision, but from help:
The exact range of values, which can be used with floats and doubles to get correct results from arithmetic operations, looks as follows:
Float: +- 1.175494e-38 till +- 3.402823e+38
Double: +- 2.2250738585072013e-308 till +- 1.7976931348623157e+308
More information about the 'IEEE 754' standard you can get on Wikipedia.
It should work with @ricardo_sdl's numbers.
The bigger problem is that it works sometimes like in @Little John's example, and the problem is not with mod(), but with calculation.
PB5.72x64
Code: Select all
CurrentFrame.f = 3.87199997901917
Elapsed.f = 0.01600000075996
y.f=CurrentFrame + (Elapsed * 8.0)
z.f =Elapsed * 8.0
Debug y
Debug z
Debug z+CurrentFrame
Norm.
Re: Mod function returning the same value as the Divisor
Posted: Fri Oct 30, 2020 5:29 am
by Tawbie
Hi Norm,
The issue with floats here is not the range that they support but the precision with which a float can represent a decimal number, before rounding occurs. The problem with the original code is not the Mod() function but the rounding that occurs when CurrentFrame is set equal to the result of the Mod() function. The Mod() function result is 3.99999998509885 but this is rounded to 4.0 when assigned to CurrentFrame to fit within a float's precision limits (significant digits). Without this rounding, you would get the expected result as illustrated in the code below:
Code: Select all
CurrentFrame.f = 3.87199997901917
Elapsed.f = 0.01600000075996
; CurrentFrame = Mod(CurrentFrame + Elapsed * 8, 4)
If Mod(CurrentFrame + Elapsed * 8, 4) >= 4.0
Debug "instead is 4 or more"
Else
Debug "CurrentFrame should be zero"
EndIf
Little John's code appears to give the expected result but it is actually calculating a different thing. The original code was attempting to test the remainder of 3.99999998509885 / 4 = 3.99999998509885 which is less than 4 but is not zero!. Little John's code is testing the remainder of 4.0/4 which equals 0.
So when working with a reasonable number of significant digits, it is safer to use doubles.
Re: Mod function returning the same value as the Divisor
Posted: Fri Oct 30, 2020 9:28 am
by Martt
Tawbie wrote:Hi Norm,
The issue with floats here is not the range that they support but the precision with which a float can represent a decimal number, before rounding occurs.
Or you use mpdecimal library
https://www.bytereef.org/mpdecimal/
Re: Mod function returning the same value as the Divisor
Posted: Fri Oct 30, 2020 4:33 pm
by ricardo_sdl
Those rounding problems man!
Mod works as expected!
Looking at the Math library on the Free Pascal compiler, I found this code:
Code: Select all
Procedure.f FMod(a.f, b.f)
ProcedureReturn a - b * Int(a / b)
EndProcedure
I think it should be robust against rounding, returning zero on the cases where a and b really close but not equal.
Re: Mod function returning the same value as the Divisor
Posted: Fri Oct 30, 2020 6:12 pm
by Little John
Tawbie wrote:Little John's code appears to give the expected result but it is actually calculating a different thing. The original code was attempting to test the remainder of 3.99999998509885 / 4 = 3.99999998509885 which is less than 4 but is not zero!. Little John's code is testing the remainder of 4.0/4 which equals 0.
You are right. I am sorry for having posted misleading code.
