Mod function returning the same value as the Divisor

Just starting out? Need help? Post your questions and find answers here.
ricardo_sdl
Enthusiast
Enthusiast
Posts: 141
Joined: Sat Sep 21, 2019 4:24 pm

Mod function returning the same value as the Divisor

Post 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! :o
You can check my games at:
https://ricardo-sdl.itch.io/
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Mod function returning the same value as the Divisor

Post 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
Tawbie
User
User
Posts: 35
Joined: Fri Jul 10, 2020 2:36 am
Location: Australia

Re: Mod function returning the same value as the Divisor

Post 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
normeus
Enthusiast
Enthusiast
Posts: 470
Joined: Fri Apr 20, 2012 8:09 pm
Contact:

Re: Mod function returning the same value as the Divisor

Post 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.
google Translate;Makes my jokes fall flat- Fait mes blagues tombent à plat- Machte meine Witze verpuffen- Eh cumpari ci vo sunari
Tawbie
User
User
Posts: 35
Joined: Fri Jul 10, 2020 2:36 am
Location: Australia

Re: Mod function returning the same value as the Divisor

Post 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.
User avatar
Martt
User
User
Posts: 18
Joined: Sat Dec 23, 2017 4:03 pm
Location: The Netherlands

Re: Mod function returning the same value as the Divisor

Post 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/
ricardo_sdl
Enthusiast
Enthusiast
Posts: 141
Joined: Sat Sep 21, 2019 4:24 pm

Re: Mod function returning the same value as the Divisor

Post by ricardo_sdl »

Those rounding problems man! :x
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.
You can check my games at:
https://ricardo-sdl.itch.io/
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Mod function returning the same value as the Divisor

Post 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. :(
Post Reply