精度与系统精度.nanoTime()

2022-09-01 17:35:57

System.nanoTime() 的文档说了以下内容(强调我的)。

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

在我看来,这可以用两种不同的方式解释:

  1. 上面粗体的句子指的是单个返回值。然后,精度和准确性要从数字意义上来理解。也就是说,精度是指有效位数的数量 - 截断的位置,准确性是数字是否正确(例如这里顶部答案中描述的“精度”和“准确性”有什么区别? )

  2. 上面粗体的句子指的是方法本身的能力。然后,精度和准确度应理解为飞镖板类比(http://en.wikipedia.org/wiki/Precision_vs._accuracy#Accuracy_versus_precision:_the_target_analogy) 所示。因此,低精度,高精度=>错误值被以高精度反复击中:想象物理时间静止,nanoTime()的连续调用返回相同的数值,但它与自参考时间以来的实际经过时间相差一些恒定偏移。

哪种解释是正确的?我的观点是,解释2意味着使用nanoTime()的时间测量(通过减去两个返回值)将正确到纳秒(因为测量中的常数误差/偏移将被消除),而解释1不能保证测量之间的这种一致性,因此不一定意味着高精度的时间差测量。


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

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

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

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

由于数值溢出,跨度大于约 292 年(263 纳秒)的连续调用的差异将无法正确计算经过的时间。

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


答案 1

在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

因此,从本质上讲,它不会每纳秒更新一次,这与人们直观地期望其精度相反。在Windows系统中,它在引擎盖下使用API(根据本文),实际上似乎可以提供大约640 ns的分辨率(在我的系统中!nanoTimeQueryPerformanceCounter

请注意,它本身根本不能有任何准确性,因为它的绝对值是任意的。只有连续调用之间的差异才有意义。这种差异的(不)精度在1微秒的大致值内。nanoTimenanoTime


答案 2

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

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


推荐