Tip: Use Doubles for time ratios

BlitzMax Forums/BlitzMax Programming/Tip: Use Doubles for time ratios

Grey Alien(Posted 2006) [#1]
I've been fiddling with my Fixed Rate Logic code and realised that the floats I was using to return a delta value were totally imprecise for the job when the millisecs counter is quite high, so changed to doubles and now it works lush. Plus I also found a potential problem with the rounding of consts even if you typecast them as doubles!

see this:

Print "" 'blankline

time = MilliSecs()
Print "millisecs="+time

myfloat# = time/5.0
Print "float ="+myfloat

mydouble:Double = time/5.0
Print "double="+mydouble

Const MyConst = 43251254
Print "const =" + Double(MyConst/5.0)

Print "direct=" + Double(43251254/5.0)

MyInt = 43251254
Print "Int   =" + Double(MyInt/5.0)


- Code shows that float doesn't give precise enough value when dividing millisecs()
- Code shows that constants or direct constants passed into the equation round!
- Code shows that ints passed into the equation work as expected.

Wonder if this a bug with Constants?

This sort of ifo is very useful for delta timing and 3D apps and physics simulations etc.


Dreamora(Posted 2006) [#2]
No bug with constant. But 5.0 is float, myconst is int -> float operation.

You would need to make 1 of it double and dividing then. Make it a double afterwards does not change anything on the division arithmetik


Floyd(Posted 2006) [#3]
There's no reason not to use doubles, so go ahead.

But for Fixed Rate Logic code it should not matter. Millisecs() may be very large, but delta values should be quite small. Single precision would be plenty.


Grey Alien(Posted 2006) [#4]
Dreamora: I didn't 100% follow that. Why is MyConst different from MyInt if both start as Integers? Why should the results be different? Try this

Const MyConst:Int = 43251254
Print "const =" + Double(MyConst/5.0)
Local MyInt:Int = 43251254
Print "Int   =" + Double(MyInt/5.0)

my output:
const =8650251.0000000000
Int   =8650250.8000000007


Floyd: It might be fine for normal delta timing code, but the way my fixed logic code works, it isn't fine. Doubles are needed. Also surely doubles are slower than floats or can modern non-64bit CPUS handle both at the same speed?


TartanTangerine (was Indiepath)(Posted 2006) [#5]
As long as you ensure you cast the Int or Const before you do the calculation you should be safe.
Const MyConst:Int = 43251254
Print "const =" + Double(Double(MyConst)/5.0)
Local MyInt:Int = 43251254
Print "Int   =" + Double(MyInt/5.0)

My Output
const =8650250.8000000007
Int   =8650250.8000000007



Dreamora(Posted 2006) [#6]
Consts are handled by a different optimation logic than a value that is interpreted at runtime ... This will give a slightly different precision normally unless you cast them before calculation as Indiepath showed in his example.


Robert Cummings(Posted 2006) [#7]
I don't think it's possible to tell the difference. What kind of timing scheme do you have where floats are insufficient in granularity for movement?


Grey Alien(Posted 2006) [#8]
Indiepath: Yeah that's cool but I was just really making the point that they are different, which I found odd. Dreamora's explanation makes sense as you can clearly see they are handled differently.

One Eyed Jack: I've improved the "retro64" timing method, which was Fixed Rate Logic, to avoid slight "stuttering" movement on sprites cause by sometimes moving one pixel and then other times 2 etc because of rounding errors (well the moire effect in motion). Now after the logic loop has run for a certain number of whole iterations, the final iteration uses a Delta value from 0 to 1 which ensures all objects can be moved by a fraction of their nomal logical amount. This means much smoother anim. I needed the double because of this code segment:

			Local TmpMS:Double 'float isn't accurate enough because Millisecs is such a big number
			Repeat
				TmpMS = MilliSecs()/MS
		
				'little sanity check here in Case the timer flips back To 0 :)
				If TmpMS < LastTime Then LastTime = TmpMS - LastNumTicks
		
				NumTicks = TmpMS - LastTime
			Until NumTicks > 0
			LastTime = TmpMS
			LastNumTicks = NumTicks		


All the variables were floats, now they are doubles. MS=5.0 btw. With floats NumTicks always ended in .0 or .5 which isn't right. With doubles it ends in .2 or .4 or .6 or .8 or .0 which is correct. My PC has been on all day so Millisecs() is quite high.

Standard Delta timing can be too "coarse" for certain games esp. with fast moving objects and collisions and poss frame rate drops. The fixed rate logic never cocks up collisions and is perfectly smooth now I've improved it, whereas before it could suffer from very slight judders every so often due to the logic sometimes looping say twice and other times three times in a frame thus the objects didn't move the same amount each frame and your eye picked this up.


Michael Reitzenstein(Posted 2006) [#9]
That can be easily done with integer math and a float. The delta is ( Millisecs( ) - OldMS ) which will be small, and then divide that by 5.


Yan(Posted 2006) [#10]
As an aside...You just need to tell BMax that you want to use doubles and casting the output is just plain silly as it's too late by then anyway...
Const MyConst:Int = 43251254
Print "const =" + MyConst / 5!

Local MyInt:Int = 43251254
Print "Int   =" + MyInt / 5!



Grey Alien(Posted 2006) [#11]
Michael Reitzenstein: yup so it can.

Ian: Oh yeah, now I know about ! cool.