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

Evg*_*eni 19 java comparison time integer-overflow

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

比较两个nanoTime值

long t0 = System.nanoTime();

...

long t1 = System.nanoTime();

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

有两件事我不清楚:

  1. 为什么要检查t1 < t0是否t1被带走t0?我的理解是纳米时间总是在增加.所以,我宁愿检查一下t1 > t0.
  2. 让我们假设这是一个错字,他们意味着正确的检查t1 - t0 > 0.我仍然不明白为什么这是正确的检查方式而不是t1 > t0.他们提到数字溢出,我不太明白他们的意思.关于数值溢出,这里提到的是:

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

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

Mik*_*kis 9

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

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

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

(我强调的是.)

这意味着您没有任何保证,在产生的长值将从正变为负值时,您的代码将不会正常运行.

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

目前,我的JVM返回了一些像3496793269188这样的数字,但是如果它想要的话,它可能会返回一些非常接近9223372036854775807的数字(也就是说Long.MAX_VALUE),这将使得从正面转为负面.

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


And*_*niy 7

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

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

        System.out.println(t1 < t0);
        System.out.println(t1 - t0 < 0);
Run Code Online (Sandbox Code Playgroud)

它会给

true
false
Run Code Online (Sandbox Code Playgroud)

虽然在数学上两个表达式都是真的.但在我们的情况下,我们知道,time手段的负值,它是溢出的,因此它应该真正大于正数.


Mil*_*lan 3

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

顺序是这样的:2^63-2, 2^63-1, -2^63, -(2^63-1) ...

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

对于两个值t0t1(其中 t1 在 t0 之后捕获),您不应该使用t1 < t0(来检查false) 而是t1 - t0 < 0,类似地,您不应该使用t1 > t0(来检查true) 而是t1 - t0 > 0

或者将其形式化:

对于两个“纳米”值t0t1,在以下条件t1后捕获其中t0(t1 - t0 > 0) == true只要t1和之间的周期t0<= 2^63 ns。

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

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

正确的?:)

溢出时

为了便于解释,lats 假设使用 8 位存储的类型(而不是 long 使用的 64 位),因此二进制到十进制的表示形式为:

0000 0000 => 0
0000 0001 => 1 (2^0)
0000 0010 => 2 (2^1 + 2^0)
...
1111 1111 => 255 (2^7 + 2^6 + ... + 2^1)
Run Code Online (Sandbox Code Playgroud)

现在下一个数字自然是当你增加 1 时。将 1 添加到二进制 1111 1111 将产生 1 0000 0000

(1) 0000 0000 => -256 !!!通常,位置 8 上的溢出位将表示(负权重)符号位

first following value is adding 1 to most-right position 
(1) 0000 0001 => -256 + 2^0 = -255
(1) 0000 0010 => -256 + 2^1 = -254
(1) 0000 0011 => -256 + 2^1 + 2^1 = -253
...
Run Code Online (Sandbox Code Playgroud)

你明白了

其根源在于依赖二进制值的底层硬件注册表实现。您可以在这里阅读更详细的解释,例如: http: //www.allabout Circuits.com/textbook/digital/chpt-2/binary-overflow/