millisec() concern

BlitzMax Forums/BlitzMax Programming/millisec() concern

Johnsprogram(Posted 2008) [#1]
This is only a paranoia question...
When using millisec(), does it have a maximum value that then reached resets the counter back to zero?


ziggy(Posted 2008) [#2]
No, when the maximum is reached, it starts to be negative


TomToad(Posted 2008) [#3]
But that doesn't happen unless the computer has been running for quite a while without a reboot. I believe somewhere around 24 days.


xlsior(Posted 2008) [#4]
But that doesn't happen unless the computer has been running for quite a while without a reboot. I believe somewhere around 24 days.


Just out of curiosity, does Hibernate affect that, or does it reset back to 0 after a resume from hibernation?


Dreamora(Posted 2008) [#5]
Hibernate does not reset the uptime of the system.
So a system thats in hibernate for 25 days will have negative millisecs actually. but thats no problem. Due to AppSuspended and AppResumed you are able to "cut" that time if you need it.
At best you only work with inframe time differences and let the rest outside of your logic calculation.
But even if you don't do it: the millisecs is only a problem for 2 milliseconds: 1. when it goes from + max to - max and 2. when it goes from -1 to 0. but only the first one causes a massive error.


ImaginaryHuman(Posted 2008) [#6]
This will double the length of time that the system can run before you get a problem:

Local Milli:Long=Long(MilliSecs())+4294967296:Long


It basically turns the negative Integer into a Long. Negative numbers will start out being the largest negative value possible and then approach 0. So if you add that long number to the value it will put it back into the positive range. The number is 2^32, but what you're really doing is adding 2^31 twice.

Still, after around 48 days (almost 7 weeks) the number is going to jump from about (2^32)-1 back to 0.

You could handle that in two ways. You could store the previous value of Milli into another variable in the previous frame and if the new Milli is < the old one then you need to take some action. It's then up to you whether you want to cater for 1 wraparound event (extending you to 14 weeks) or to use the full scope of a Long by allowing up to 31 wraparounds - which would be about 2 years.

To do that you'd just need to count how many times the new Milli has been < the old Milli and based on that counter, generate the correct time using something like `Milli+(2^(31:Long+Long(Count)))`. (not sure on the casting you'd need to ensure you get a Long result not clipped to integer length)

You could extend that time frame very slightly by dealing with the Long turning into a negative value. But that's another story.

So if you're worried about your Millisecs wrapping to a negative value after 24 days, use something like the above method and then you don't have to worry. Note, though, that Milli starts counting from the time you switch on the computer not the time when you started running your application, so by the time you start up your app you my have already used up quite a lot of time.


Zethrax(Posted 2008) [#7]
This is the correct way to check for a timeout.

Where 'current_time' is the current time in milliseconds (set it from the MilliSecs() function at the start of an update loop).

If ( current_time - deadline_time ) > 0
Print "Timeout occurred"
Else
Print "No timeout occurred"
EndIf

To set the value of 'deadline_time' when you create the timeout, just add 'current_time' with however milliseconds ahead you want the timeout to occur.

eg.
deadline_time = current_time + 10000 ; Sets a ten second timeout.


Graphics 800, 600, 0, 2

Const MAX_POSITIVE = 2147483647
Const MAX_NEGATIVE = -2147483648

current_time = MAX_POSITIVE
deadline_time = MAX_POSITIVE + 1

;current_time = -1
;deadline_time = 0

;Print "Millisecs() wrapover occurs every " + ( ( ( ( MAX_POSITIVE / 1000.0 ) / 60.0 ) / 60.0 ) / 24.0 ) + " days."
Print 
Print "current_time = " + current_time
Print "deadline_time = " + deadline_time
Print
Print "Time remaining = " + ( deadline_time - current_time )
Print

; -- Check if 'current_time' has exceeded 'deadline_time'. This should work even if one or both times have
;~ wrapped over to negative, or if one or both times have wrapped from negative to zero or positive.
;~ Substitute '>=' for '>' when testing if 'current_time' has reached or exceeded 'deadline_time'.
If ( current_time - deadline_time ) > 0
	Print "Timeout occurred"
Else
	Print "No timeout occurred"
EndIf 
;^^^^^^

WaitKey ()

End 



TomToad(Posted 2008) [#8]
You could also use the high resolution timers which start when the program is launched, not when the computer is rebooted. I wrote a module for Windows a while ago.
http://www.blitzbasic.com/codearcs/codearcs.php?code=2059


Digital Anime(Posted 2008) [#9]
I noticed many have troubles calculating the elapsed time when timer jumps back to a negative number.

I wanted to share this code with ya all :

Strict

Global newtime:Int = MilliSecs()
Global oldtime:Int = MilliSecs()
Global elapsedtime:Int = 0

Repeat

oldtime = newtime
newtime = MilliSecs()

If oldtime < newtime Then 
'using 2147483648 to make sure newtime and oldtime are positive all the time.
elapsedtime = (2147483648 + newtime) - (2147483648 + oldtime)
Else
'In case if the newtime is smaller than the oldtime (after reset) this calculation is done to make sure you get the correct elapsed time.
elapsedtime = (2147483648 + newtime) - (oldtime - 2147483648)
EndIf

Delay 5000
Print elapsedtime + " MilliSecs elapsed after last print command!"

Until KeyHit(Key_ESCAPE)


I never tested this code for 24 days to be sure it works, and is just something I came up with. Could anyone test this or leave some comments.