System.nanoTime()的精度与准确度

时间:2012-07-12 13:11:43

标签: java nanotime

System.nanoTime()的文档说明如下(强调我的)。

  

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。返回的值表示纳秒,因为某些固定但是任意时间(可能在将来,因此值可能为负)。 此方法提供纳秒精度,但不一定是纳秒精度。不保证值的变化频率。

正如我所看到的,这可以通过两种不同的方式来解释:

  1. 上面粗体中的句子是指个别返回值。然后,从数值意义上理解精度和准确度。也就是说,精度是指有效数字的数量 - 截断的位置,准确度是指数字是否正确(如此顶部答案中所述) What is the difference between 'precision' and 'accuracy'?

  2. 上面粗体中的句子指的是方法本身的功能。然后,通过飞镖类比来说明精度和准确度 (http://en.wikipedia.org/wiki/Precision_vs._accuracy#Accuracy_versus_precision:_the_target_analogy)。 因此,低精度,高精度=&gt;错误的值被高精度地反复击中:想象物理时间静止不动,nanoTime()的连续调用返回相同的数值,但是从参考时间开始经过一些常数< / em> offset。

  3. 哪种解释是正确的?我的观点是,解释2意味着使用nanoTime()(通过减去两个返回值)的时间差异的度量将是纳秒的正确(因为测量中的恒定误差/偏移将是虽然解释1不能保证测量之间的符合性,因此不一定意味着高精度的时差测量。


    2013年4月15日更新: System.nanoTime()的Java 7文档已更新,以解决可能与之前措辞混淆的问题。

      

    返回正在运行的Java虚拟机的高分辨率时间源的当前值,以纳秒为单位。

         

    此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。返回的值表示纳秒,因为某些固定但任意的原点时间(可能在将来,因此值可能为负)。在Java虚拟机的实例中,此方法的所有调用都使用相同的原点;其他虚拟机实例可能使用不同的来源。

         

    此方法提供纳秒级精度,但不一定是纳秒级分辨率(即值的变化频率) - 除了分辨率至少与currentTimeMillis()的分辨率一样好之外,不做任何保证。

         

    跨越大于约292年(2 63 纳秒)的连续调用的差异将无法正确计算由于数值溢出而导致的经过时间。

         

    只有在计算在Java虚拟机的同一实例中获得的两个此类值之间的差异时,此方法返回的值才会有意义。

4 个答案:

答案 0 :(得分:12)

在Clojure命令行中,我得到:

user=> (- (System/nanoTime) (System/nanoTime))
0
user=> (- (System/nanoTime) (System/nanoTime))
0
user=> (- (System/nanoTime) (System/nanoTime))
-641
user=> (- (System/nanoTime) (System/nanoTime))
0
user=> (- (System/nanoTime) (System/nanoTime))
-642
user=> (- (System/nanoTime) (System/nanoTime))
-641
user=> (- (System/nanoTime) (System/nanoTime))
-641

所以基本上,nanoTime不会每纳秒更新一次,这与人们对精度的直观期望相反。在Windows系统中,它使用了引擎盖下的QueryPerformanceCounter API(根据this article),实际上它似乎提供了大约640 ns的分辨率(在我的系统中!)。

请注意,nanoTime本身不能具有任何准确度,因为其绝对值是任意的。只有连续nanoTime次调用之间的差异才有意义。该差异的(in)准确度在1微秒的范围内。

答案 1 :(得分:8)

第一种解释是正确的。在大多数系统中,三个最低有效数字始终为零。这实际上提供了微秒精度,但是以纳秒的固定精度水平报告。

事实上,现在我再次看一遍,你的第二种解释也是对正在发生的事情的有效描述,甚至更多。想象冻结的时间,报告将始终是相同的错误纳秒数,但如果被理解为整数微秒,则更正。

答案 2 :(得分:4)

System.currentTimeMillis()&amp;之间差异的一个非常有趣的特征。 System.nanoTime() System.nanoTime()不会因挂钟而改变。我在具有大量时间漂移的Windows虚拟机上运行代码。当NTP纠正漂移时,System.currentTimeMillis()每次可以向后或向前跳1-2秒,从而使准确的时间戳无意义。 (Windows 2003,2008 VPS版本)

但是,

System.nanoTime()不受更改挂钟时间的影响,因此您可以通过NTP检索时间并根据System.nanoTime()应用更正,因为最后检查了NTP并且您有更多在不利的挂钟条件下准确的时间比System.currentTimeMillis()

这当然是违反直觉的,但有用的知识

答案 3 :(得分:1)

如果像我这样的人一次又一次地读到这个问题并再次仍然有点理解它,这里有一个更简单(我希望)的解释。

Precision是关于您保留多少位数。每个:

long start = System.nanoTime();
long end   = System.nanoTime();

将是一个精确的数字(很多数字)。

由于accuracy只是进行比较,因此对System.nanoTime的单独调用毫无意义,因为它的值非常随意并且不依赖于我们可以测量。区分它的准确性的唯一方法是对它进行两次不同的调用,因此:

 long howMuch = end - start;

具有纳秒精度。事实上在我的机器上,差异是0.2 - 0.3微秒。