Negative Millisecs()

BlitzMax Forums/BlitzMax Programming/Negative Millisecs()

Tibit(Posted 2006) [#1]
I started to use millisecs as a timer that counter upwards. 1..2..3..4..5..6 and so on. Then I learnt that after some days, or on linux systems, the counter goes into the negative. How does it count when it comes to negative?

Is it -9...-8...-7...-6...-5 ?
or
-7...-8...-9...-10...-11...-12?

And when it laps? How does it start over?

And to measure the time from A to B, is the correct way to do it like this:

timer:Int = millisecs()
' ex time = 400
' or time = -600

DoSomethingTedious() 'Returns 500ms later

timeTaken = millisecs() - time
' Should be: timeTaken = 900 - 400 ----------> 500 ok!
' or negative : timeTaken = -1100 - (-600) --> -500 ok?
' Should I use abs() or am I doing something wrong?



And when you want to get a time Ex. when 500ms have passed.


startTime = millisecs()
' Ex1. StartTime = 800
' Ex2. StartTime = -800

Loop
If millisecs() - startTime => TimePassed Then DoSomething()
'Millisecs() - 800
'Ex. 900 - 800 = 100ms passed
' If 100ms => 500ms Then.. ok!

'For negative:
' Millisecs() + 800
' Ex. -900 + 800 = 100ms
' If 100ms => 500ms Then.. ok! Seems to work, right?
EndLoop



Is this how millisecs() was intended to be used? Is there more to it?


Grey Alien(Posted 2006) [#2]
I would assume it wraps at the 2 billion mark back to minus two billion (then count up towards 0) if it's signed. Otherwise it would wrap from 4 billion odd to 0.

You second comment 'For negative shows -900+800 = 100ms, this is wrong it will be -100ms. Anyway, after 100ms, it should go up to -700ms and then -700 --800 = 100 (because -- = +) :-)


Eikon(Posted 2006) [#3]
After 24 days of uptime or so, the integer value overflows and it goes negative -2,147,483,648 or whatever, and then begins counting back towards 0. I use a custom MilliSecs function that starts counting at 0 to solve the problem.


Brucey(Posted 2006) [#4]
wouldn't this solve the problem?

Local startTime:Long = millisecs()

....

Local timeRunning:Long = millisecs() - startTime


(at least until 2038...) :-)


Grey Alien(Posted 2006) [#5]
There's no problems with it counting negative as the differences are still positive. The only problem is the instance when it wraps over, you may get a ridiculous value, but you can protect against that.


Eikon(Posted 2006) [#6]
If you like to use

If MilliSecs() >= myTime + 100

there will be problems with it counting negative. Instead of changing all my instances of that, I just start from 0.


sswift(Posted 2006) [#7]
I would avoid using Millisecs() for timing things directly in my game.

I do the following:

	Current_Time	 = MilliSecs()
	Game_Start_Time  = Current_Time
						
	Repeat
		
		SetClsColor 0, 0, 0
		Cls
	
		Repeat 
			Time_Old		= Current_Time						' Store start time of last frame.
			Current_Time 	= MilliSecs()						' Get the current time.  Use this instead of Millisecs() from here on if you need the time.
			Time_Delta 		= Current_Time - Time_Old			' Calculate how long last frame took to render, in milliseconds.
			Time_Delta_Sec# = Float(Time_Delta)/1000.0			' Convert frame time to seconds.
		Until (Time_Delta > 0) And (Time_Delta < 250)			' Handle unnaturally long pauses between frames gracefully.
				
		FPS = 1000.0 / Float(Time_Delta)



See that bit after Until? That handles both when the user tabs out of the app and back, and when millisecs wraps to 0.

Also, when Millisecs() wraps to negative, it counts towards 0, so if Current_Time = -100 and Time_Old = -200, then Time_Delta = 100, which is correct.

The last bit of the puzzle isn't in the code above. I have a Game_Time variable which I add Time_Delta to each frame while the game is not paused. While it is likely someone might leave their PC running for 23 days straight and you might have a negative Millisecs() to deal with, it's not so likely that they will leave your game running for that long, so you need not worry about your Game_Time timer overflowing. But if you are... Make it a long. A long will not overflow until around 160 million years have passed. :-)


ImaginaryHuman(Posted 2006) [#8]
All you need to do is check if the millisecs is larger than a given value and then modulo it with that value and adjust whatever other parameters you have so your whole thing still works... or put the `total millisecs` from all the modulo'd millisecs into a Long.


Tibit(Posted 2006) [#9]
Thanks for all the great response.

Okey so it counts from lowest negative to 0 to highest int, then it jumps to lowest negative and counts upwards towards 0 again.

Brucey thanks, that was a nice idea. I'm going to use that one. Allows me to use A > B and B < A with current time instead of A - B > 0 and B - A > 0.

Sswift, what I do not really understand is the Repeat-Until loop you have inside you main loop. Is this like a delay?

Until (Time_Delta > 0) And (Time_Delta < 250) - Is not Time_Delta always be less than 0?

With a FPS of 75 the frametime should be less than 13 ms. FrameTime = 1000/FPS. And this would be the total time for Graphics, Logic, AI, Effects and more. Or did you mean to draw/update everything then run some delay until time reached?

AngelDaniel, How did you mean to use Mod with millisecs? How fast is mod?


Grey Alien(Posted 2006) [#10]
I'm pretty sure sswifts code means that if there is a big delay due to external influences OR the clock has wrapped round, then it will take another reading. Also Time delta is either 0 or greater normally as it's measure in MS: Time_Delta = Current_Time - Time_Old

re: Mod considering you are only calling it ONCE per frame, I really wouldn't worry :-)


sswift(Posted 2006) [#11]
Time_Delta should always be greater than 0, not less than 0, so with an FPS of 75 it will be 13.

The reason I check to see if it is less than 0 is just in case the code is running so fast that it executed in less than a millisecond. That would cause stuff to crash when it divides by 0. And I check if it is greater than 250 because that's only gonna happen if the FPS drops below 4fps, like if the hard drive starts thrashing for a moment or the user tabs out of the game. Saves them from getting killed because everything went choppy for a moment and they missed something important.


Tibit(Posted 2006) [#12]
Ah so it works like a pause when the FPS drops very low, instead of lag in form of warping.

Wait a minute, I think I confused myself. Yes, I agree Delta_Time, which is the same as frametime, is always greater or equal to 0. However your loop loops when it is greater than 0 or less than 250. Which means it will loop forever unless the logic suddendly takes less than a millisec to do? Or maybe I missunderstood where you put the UpdateEverything() function?


Grey Alien(Posted 2006) [#13]
It's not a while loop, it's a repeat until loop so as soon as Delta_Time goes over 1, it exits the look and this is where the logic would be updated and then the drawing would be done.


sswift(Posted 2006) [#14]
Wave:
No, it won't loop forever, because eventually one read of millisecs will be at the next millisecond when the other was at the previous. But I suppose it's possible it could loop a few times. Anyway I haven't ever noted it being an issue, even when the screen is blank and the FPS counter is stuck at 1000.


Damien Sturdy(Posted 2006) [#15]
FYI Mod is plenty fast, not sure why you'd worry. I use it thousands of time a loop, maybe tens of thousands.


Tibit(Posted 2006) [#16]
Sorry did not think about until = not while :)