# An Interesting Scenario with Windows Timers

This topic is 3845 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Today, A small and not much noticable problem in my program has occured. After a short time of trying to solve it, I was so close to giving up, but eventually it led me to reveal A very interesting scenario/problem (in my opinion). Perhaps some of you are familiar with it. I appologize for the long story but I believe it is not much complicated and it also has almost no source code that you will have to decipher :) I do have a few question in the end that are based on what I've wrote. It all started as a weird problem in my Direct3D program: The rotation of a model was quite unsmooth although the FPS was definitely high enough. I've made lots of rotations in various programs in the past with the same code and no such problem has ever occured. After some investigation I've noticed that the statement '((float) timeGetTime () / 1000.0f)' has changed each 5 frames or so, even though the timeGetTime () returned different values each frame. I guess that at this point most of you have already figured out why this is happening. However, I was completely confused and and wrote a simple test program. Here is the first code I wrote:
	DWORD times [100], tm;//list of times, temporary time
for (int i = 0; i < 100; i++) {
tm = (DWORD) timeGetTime ();
if (i != 0 && tm == times [i - 1]) {
i--;
continue;
}
times [i] = tm;
}


All this does is simply filling the 'times' array with 100 unique closest as possible times returned by timeGetTime (). This code (the 'for' loop) ran for an unnoticable amount of time (actually 100 ms) and the values in the array were x,x+1,x+2,x+3, ... ,x+99. So far so good. Now I've changed the 'times' and 'tm' variables from DWORD to double (and changed the casting to double as well). Everything was the same this time. But now I've changed them to floats. I was completely surprised: It took about 6 seconds to complete the loop! Accordingly, the difference between the numbers in the 'times' array was about 60 (ms). Ok so again, most of you probably know why this is happening, and so do I after investigating it for too long. Here is my explanation (might be inaccurate, so please correct me): the 'float' type was designed (or just turned out) so that it would be able to hold more accuracy after the floating point, but less possibility for big numbers, such as those which DWORD can hold. Since both types are 32 bit (in 32 bit systems) and DWORD can contain values as high as 4GB, float wouldn't be able to get to that number since it needs to use many bits for the fractional data (I am aware that it isn't just a simple seperation of the 32 bits into 2 unrelated groups, but it is irrelevant here). This inaccuracy causes close big numbers that are converted to floats to turn out completely the same (same 32 bit data) and thus indistinguishable. When my program ran, it actually hasn't found any difference (inside the 'if') between the 2 high number floats till the point where the real difference between them was about 60. Now this explains exactly what happend in my 3D rotation program: These 60 miliseconds are approximately the 5 equal rotation frames, due to the fact that each frame is called every 12 ms (83 FPS). <Please hold on for a little longer, I'm almost done (few questions in the end)> There is still one thing that is a bit mysterious in all this story: Why has this weird scenario never happened to me till now, and why (I assume so) is it so rare? For those of you who haven't guessed yet, the answer is extremely simple: My computer has been running for almost two weeks now! no restarts too of course. timeGetTime () retrieves the system time in miliseconds, so 12 days for instance is about 1GB of miliseconds (1/4 of the maximum value for a DWORD), and this is with no doubt high enough to cause a float to go crazy and lose its accuracy:
	float f1, f2;
f1 = (float) 1000000090;
f2 = (float) 1000000035;
f1 == f2;//true



##### Share on other sites
The problem is as you've said - the float type can holder larger and smaller numbers than integers and can hold fractions, but it can't represent every number in it's range. IEEE floats use 23 bits for the value, doubles use 52 bits, and long doubles use 64 bits. Those values are basically equal to significant figures, but in binary. A float can thus represent every integer from -2^23+1 to +2^23-1 (8388607) but past that digits will be lost.

The proper solution is to store times as DWORDs (or whatever type the functions return naturally, such as QWORD for QueryPerformanceCounter) and only use float (or double for QWORD) for the difference between times.

In other words, something like
DWORD Time1, Time2;float DeltaTime;//...DeltaTime = float(Time2-Time1) / 1000.00f;

[Edited by - Extrarius on June 3, 2007 1:20:46 PM]

##### Share on other sites

This topic is 3845 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628653
• Total Posts
2984052

• 10
• 9
• 9
• 10
• 21