6
\$\begingroup\$

I'm reading a fantastic article about game timer precision and here is a quote about 2/3 of the way into the article:

If you start your game clock at about 4 billion (more precisely 2^32, or any large power of two) then your exponent, and hence your precision, will remain constant for the next ~4 billion seconds, or ~136 years.

He doesn't give a concrete example of this though. Does this mean I would want to add 2^32 to the game clock value that I store at the beginning of each frame? Or is there a way to actually set the clock in Windows so that the numbers start at 2^32?

\$\endgroup\$

4 Answers 4

11
\$\begingroup\$

TL;DR The author is not suggesting you implement this in your game. He's telling you that the precision will be slow changing, but bad.

This means the float you're using to track your game time would start at 2^32. Because setting the number that large to start with, whatever you add on to it in the next 136 years, won't change the exponent.

Though, the precision will remain constant, it doesn't mean it's better. The precision gets worse the larger the number. Starting with a large number just means that the precision won't change over the life of the counter, but the precision is worse than starting with a small number. If you started at 0 the exponent would change frequently at first, meaning the precision changes frequently.

Concrete example:

float twoToThirtyTwo = 4294967296;
float game_time_elapsed = twoToThirtyTwo;

float getTimeElapsed() {
     return game_time_elapsed - twoToThirtyTwo;
 }

I believe overall the article is suggesting using floats for time deltas (short/small time spans) and using ints or longs for time elapsed (long/large time spans).


The author suggests a change to the code above to make it usable, since it's currently an example of how you can have constant bad precision. Change to a double:

double twoToThirtyTwo = 4294967296;
double game_time_elapsed = twoToThirtyTwo;

double getTimeElapsed() {
     return game_time_elapsed - twoToThirtyTwo;
 }

That code should give a constant good precision (around 1 microsecond) for a long time.

\$\endgroup\$
4
  • 2
    \$\begingroup\$ Im a fan of storing the times instead in big integers and converting the elapsed delta times to a float for calculations.. works nice i'd say ;D \$\endgroup\$
    – Grimshaw
    Commented Sep 18, 2012 at 0:18
  • \$\begingroup\$ ah, now I get what he's saying. The precision for numbers from 2^32 to 2^33 is the same, so we have the same precision for 2^32 seconds. thanks for the different perspective. \$\endgroup\$
    – Philip
    Commented Sep 18, 2012 at 18:48
  • 1
    \$\begingroup\$ The code above will fail miserably because it is using 'float' for game_time_elapsed. At that range the precision of a float is 256 s -- the next time that can be represented is 2^32+256. That's why I recommended two things: 1) Use a double so you have enough precision when the game has been running for a while. 2) Start at 2^32 so that the precision is consistent. The other reason to use 2^32 is so that you will instantly hit precision problems if you store elapsed game time in a float. \$\endgroup\$ Commented Sep 23, 2012 at 20:42
  • \$\begingroup\$ @BruceDawson Indeed, it wasn't meant to be used, only to show a concrete example of what I thought you were saying in your article, i.e. don't do it that way. It was made before you edited your article to be more clear. Suitable changes? \$\endgroup\$
    – House
    Commented Sep 23, 2012 at 20:46
8
\$\begingroup\$

Most games have a function that calculates the current time -- perhaps using QueryPerformanceCounter(), perhaps using GetTickCount64(), perhaps using something else. Normally this function is designed so that it initially returns zero, and then gradually returns larger numbers.

What the author is saying (and I can be definitive about this because I am the author) is:

  • The first value returned should be 2^32 instead of zero and it should smoothly increment from there.
  • The return value should be a double, not a float.
  • Comments on the article itself instead of here would be better.
\$\endgroup\$
3
  • \$\begingroup\$ Bruce, thanks for making an answer! Though I can't really agree with your last point :), you make things clearer. So you do recommend implementing this. The reasoning being that having a constant precision, even though it's not as good as it can be, is better than having better precision that's changing? \$\endgroup\$
    – House
    Commented Sep 19, 2012 at 13:16
  • \$\begingroup\$ Exactly. Having precision that varies over time is horrible. \$\endgroup\$ Commented Sep 20, 2012 at 6:11
  • \$\begingroup\$ Tom Forsyth and I debate whether it is better to use 64-bit fixed point or 64-bit doubles. I find the convenience of doubles significant for games because everything we do with time is floating-point calculations. If it's going to be floating-point, let's go straight there. I would say, what advantage is there to using fixed-point? Double can have consistent precision, plenty of precision, and is not error-prone with an appropriate start point. I don't think that developer convenience is irrelevant. Double allows natural units, instead of unwieldy large numbers. \$\endgroup\$ Commented Sep 20, 2012 at 6:14
2
\$\begingroup\$

Here's another discussion on game timer implementation and accuracy, complete with source code, that may help you with your game timer requirements.

Cygnon's Blog: Game Programming Adventures

\$\endgroup\$
1
  • 1
    \$\begingroup\$ In case that link goes dead: the poster suggests using Bresenham's line algorithm, with the (high-frequency) system clock as the x axis and the (low-frequency) game clock as the y axis. \$\endgroup\$ Commented Jun 15, 2014 at 15:37
1
\$\begingroup\$

From Tom Forsythe's article (which is linked from Bruce's article, but not really discussed:

One "solution" [to floating point precision problems] is to turn on double precision, because then you get more bits. Yeah, but you've just shuffled the problem around. Doubles have exactly the same weaknesses [as floats] - all you've done is shuffle the problems into a corner, stuck your fingers in your ears and yelled "lalalalalala". They'll still come back to bite you, and because it's double precision, it'll be even rarer and even harder to track down. And they're slower on most machines, so you've hurt your execution speed.

(my clarifications in bold)

Precision problems make floats and doubles just a fundamentally bad choice for representing absolute time. This is why Windows doesn't use them to represent absolute time. This is why OS X doesn't use them to represent absolute time. This is why Linux, BSD, Solaris, and every other OS under the sun doesn't use them to represent absolute time.

If you're storing the absolute game time, you really are better off using fixed point integers. Reliable, repeatable, and with consistent precision across their whole range. "Because I like seconds" is a pretty feeble reason to move to imprecise and error-prone storage for something as critical to a game as its internal clock, if you ask me.

\$\endgroup\$
3
  • \$\begingroup\$ Agreed. Before his article was edited it seemed that it could go either way. I was surprised that the author promoted the use of floating point, especially with large numbers. Perhaps if he comes back he can answer the "why?" part of the answer. \$\endgroup\$
    – House
    Commented Sep 20, 2012 at 4:48
  • 1
    \$\begingroup\$ At the recommended range (2^32 and beyond) a double has nanosecond precision, which I would hardly call imprecise. I'm also not clear as to what is "error-prone" about a double. I would claim that by using natural units it is less error prone than, for instance, the 100 ns units of some Windows timers. What is imprecise and error-prone about my suggestion? \$\endgroup\$ Commented Sep 23, 2012 at 20:45
  • 1
    \$\begingroup\$ timeA - timeB + timeB == timeA (and similar simple algebraic operations). Works with integers. Not guaranteed with floats or doubles, just because of the way that floating point numbers work on computers. \$\endgroup\$ Commented Sep 23, 2012 at 22:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .