如何比较两个纳米时间值? [javadoc混淆]

时间:2015-11-30 10:38:25

标签: java time comparison integer-overflow

我已经阅读了System.nanoTime()的javadoc,这一切看起来都很清楚。直到我到达最后一段:

  

比较两个nanoTime值

     

long t0 = System.nanoTime();

     

...

     

long t1 = System.nanoTime();

     

应该使用t1-t0< 0,不是t1< t0,因为数字溢出的可能性。

有两件事我不清楚:

  1. 如果在t1 < t0之后t1t0检查,为什么会检查t1 > t0?我的理解是纳米时间总是在增加。所以,我宁愿检查t1 - t0 > 0
  2. 我们假设这是一个错字,他们的意思是正确的检查是t1 > t0。我仍然不知道为什么这是正确的检查方式而不是angulartics-google-analytics.min.js。他们提到数字溢出,我不太明白他们的意思。关于数值溢出,这里提到的是:
  3.   

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

    好的,因为纳米时间存储为长值,它最终会在292年内溢出。接下来会发生什么?它是从头开始,即最低负值-2 ^ 63?或者它是否会停止测量并返回(2 ^ 63 - 1)?

4 个答案:

答案 0 :(得分:9)

你是对的,你引用的文档部分似乎有点混乱。

但是,重要的文档部分是:

  

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

(强调我加上。)

这意味着您无法保证在产生的长值将从正变为负值时,您的代码不会正常运行。

没有什么可以保证这将在300年后发生,今天可能会发生。

目前,我的JVM返回了一些像3496793269188这样的数字,但是如果它想要的话,它可以返回一些非常接近9223372036854775807的数字(Long.MAX_VALUE),这将从正到负翻转迫在眉睫。

所以,你应该采取一切必要的预防措施。

答案 1 :(得分:7)

嗯,javadoc说实话。考虑这样的例子:

        long t0 = Long.MAX_VALUE;
        long t1 = Long.MIN_VALUE;

        System.out.println(t1 < t0);
        System.out.println(t1 - t0 < 0);

它会给出

true
false

虽然在数学上两个表达式都是真的。但在我们的情况下,我们知道,time的负值意味着它溢出,因此它应该是更大然后是正数。

答案 2 :(得分:2)

让我从问题的结尾开始。是的,如果值大于2 ^ 63-1,则值将溢出。溢出的常见实现是存储结果的最不重要的可表示位;值将换行(你可以在我的帖子底部看到溢出以供参考)

序列如:2^63-2, 2^63-1, -2^63, -(2^63-1) ...

现在回顾Javadoc我同意关于使用比较的解释令人困惑,我们自然会尝试比较t1 > t0以验证t1之后t0是否发生。 你是部分正确的。虽然我不认为这是一个拼写错误,但没有正确解释。我认为应该说:

  

对于两个值t0t1(在t0之后捕获t1),您不应使用t1 < t0(检查false)而是使用{{1同样,你不应该使用t1 - t0 < 0(检查t1 > t0)而是true

或者将其正式化:

  

对于两个'纳米'值t1 - t0 > 0t0,在t1次展位后t1被捕获: t0 只要(t1 - t0 > 0) == truet1之间的时间段<= 2 ^ 63 ns。

为什么?因为即使t0溢出(因此它是负数),结果t1也将是负但是,它将小于-2 ^ 64并且它将“溢出”回到正值价值!

只要满足t1 - t0t0之间距离的条件,就会有效!如果距离大于2 ^ 64,例如:对于t1,减法结果将为:t0 = 1; t1 = -(2^64-2)因此指定的条件(t1 - t0 = -(2^64-1))将给出不正确的结果。

右:?)

溢出

为了便于解释,lats假定使用8位存储的类型(而不是长度使用的64位),所以二进制到十进制表示为:

t1 - t0 > 0

现在下一个数字自然会增加1。 将1加到二进制1111 1111将产生1 0000 0000

0000 0000 => 0 0000 0001 => 1 (2^0) 0000 0010 => 2 (2^1 + 2^0) ... 1111 1111 => 255 (2^7 + 2^6 + ... + 2^1) 通常位置8上的溢出位将代表(负权重)符号位

(1) 0000 0000 => -256 !!!

你得到了照片

这源于底层硬件注册表实现,它依赖于二进制值。 您可以在此处阅读更详细的说明:http://www.allaboutcircuits.com/textbook/digital/chpt-2/binary-overflow/

答案 3 :(得分:2)

当t1在t0之后(t1

如果读取无符号数字,则更基本的负数会大于带符号的正数:https://en.wikipedia.org/wiki/Signed_number_representations