views:

11112

answers:

6

Accuracy Vs. Precision

What I would like to know is whether I should use System.currentTimeMillis() or System.nanoTime() when updating my object's positions in my game? Their change in movement is directly proportional to the elapsed time since the last call and I want to be as precise as possible.

I've read that there are some serious time-resolution issues between different operating systems (namely that Mac / Linux have an almost 1 ms resolution while Windows has a 50ms resolution??). I'm primarly running my apps on windows and 50ms resolution seems pretty inaccurate.

Are there better options than the two I listed?

Any suggestions / comments?

A: 

Joda time is a better replacement library if you are making calls the standard java Calendar class, otherwise stick with System.currentTimeMillis() as it is more common, allowing for more code reuse from older projects. You may want to look at JSR-310. Looks like a winner!

WolfmanDragon
+12  A: 

If you're just looking for extremely precise measurements of elapsed time, use System.nanoTime(). System.currentTimeMillis() will give you the most accurate possible elapsed time in milliseconds since the epoch, but System.nanoTime() gives you a nanosecond-precise time, relative to some arbitrary point.

From the Java Documentation:

public static long nanoTime()

Returns the current value of the most precise available system timer, in nanoseconds.

This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary time (perhaps in the future, so values may be negative). This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are made about how frequently values change. Differences in successive calls that span greater than approximately 292 years (263 nanoseconds) will not accurately compute elapsed time due to numerical overflow.

For example, to measure how long some code takes to execute:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

See also: JavaDoc System.nanoTime() and JavaDoc System.currentTimeMillis() for more info.

dancavallaro
Are you sure you know the difference between accuracy and precision? There is no way it is accurate to a nanosecond precision.
Simucal
Sorry, I meant precise. I was using the term loosely, but I agree it was confusing (and an improper use of the word).
dancavallaro
And since you want elapsed time, you don't care about accuracy, you care about precision. System.nanoTime() will give you the most precise time interval possible.
dancavallaro
@dancavallaro, thanks for the information. If you don't mind, I edited your answer to include a quote from the docs and fixed up the links
Simucal
No problem! And you did a good job, looks much better than my original answer.
dancavallaro
successive calls that span greater than approximately 292 years .... my new fav quote!
Adrian
+4  A: 

System.nanoTime() isn't supported in older JVMs. If that is a concern, stick with currentTimeMillis

Regarding accuracy, you are almost correct. On SOME Windows machines, currentTimeMillis() has a resolution of about 10ms (not 50ms). I'm not sure why, but some Windows machines are just as accurate as linux machines.

I have used GAGETimer in the past with moderate success.

PaulMorel
If you have used GAGE, would you mind answering this question on Java 2D Frameworks?http://stackoverflow.com/questions/293079/java-2d-game-frameworks
Software Monkey
I posted an answer on your thread.
PaulMorel
A: 

Yes, if such precision is required use System.nanoTime(), but be aware that you are then requiring a Java 5+ JVM.

On my XP systems, I see system time reported to at least 100 microseconds 278 nanoseconds using using the following code:

private void test() {
    System.out.println("currentTimeMillis: "+System.currentTimeMillis());
    System.out.println("nanoTime         : "+System.nanoTime());
    System.out.println();

    testNano(false);                                                            // to sync with currentTimeMillis() timer tick
    for(int xa=0; xa<10; xa++) {
        testNano(true);
        }
    }

private void testNano(boolean shw) {
    long strMS=System.currentTimeMillis();
    long strNS=System.nanoTime();
    long curMS;
    while((curMS=System.currentTimeMillis()) == strMS) {
        if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)); }
        }
    if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)+", Milli: "+(curMS-strMS)); }
    }
Software Monkey
+3  A: 

David Holmes of Sun posted a blog article a couple years ago that has a very detailed look at the Java timing APIs (in particular System.currentTimeMillis() and System.nanoTime()), when you would want to use which, and how they work internally.

Inside the Hotspot VM: Clocks, Timers and Scheduling Events - Part I - Windows

One very interesting aspect of the timer used by Java on Windows for APIs that have a timed wait parameter is that the resolution of the timer can change depending on what other API calls may have been made - system wide (not just in the particular process). He shows an example where using Thread.sleep() will cause this resolution change.

Michael Burr
A: 

I wouldn't use System.nanoTime yet, at least until I get an answer that makes sense to me on what I saw. Here's what I saw with System.nanoTime that got me scared:

    long startTimeMillis = System.currentTimeMillis();
    long startTimeNanos = System.nanoTime();

    long currentTimeMillis;
    while((currentTimeMillis = System.currentTimeMillis()) == startTimeMillis) {
    }


    System.out.println(System.nanoTime()-startTimeNanos);
    System.out.println(currentTimeMillis-startTimeMillis);

Here are some examples of the output

15269818 15

3500724 15

8624839 16

5804928 16

The figure on ellapsed nanoTime not only does not approximate ellapsed millis * 1000000, it doesn't seem to have any significant relationship to it.

What am I missing? Switching the order or removing the milliseconds print really does nothing to the overall picture I'm describing... the numbers jump around in the same overall ranges.

FYI, running from within eclipse on an old 32 bit XP box with a 1.6 JRE. Feedback appreciated.

Thanks, Ben

Ben Yogman
System.currentTimeMillis() ticks slowly — say, every day. System.nanoTime() ticks faster — say, every second. You are effectively measuring the time between some unknown start time to the next midnight — of course it's going to appear random. And from your results alone System.currentTimeMillis() only has a resolution of 15 ms, which is a good reason *not* to use it.
tc.