20

当我在 Java 中阅读 System.nanoTime() API 时。我发现这一行:

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

http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime()

比较两个 nanoTime 值

long t0 = System.nanoTime();
...
long t1 = System.nanoTime();

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

我想知道为什么t1 - t0 < 0防止溢出是更好的方法。

因为我从其他一些A < BA - B < 0.

Java Integer compareTo() - 为什么使用比较与减法?

这两件事产生矛盾。

4

4 回答 4

12

Nano 时间不是“实时”时间,它只是一个计数器,当某些未指定的事件发生时(可能计算机已启动),它会从某个未指定的数字开始递增。

它会溢出,并在某些时候变成负数。如果你t0是在它溢出之前(即非常大的正数),而你t1是在它之后(非常大的负数),那么t1 < t0(即你的条件是错误的,因为t1发生在之后t0).....

但是,如果你说t1 - t0 < 0,那么神奇的是,由于相同的溢出(未溢出)原因(非常大的负数减去非常大的正数将下溢),结果将是 t1 之后的纳秒数t0...... .而且会是对的。

在这种情况下,两个错误确实使一个正确!

于 2013-08-24T01:52:02.813 回答
10

t0 - t1 < 0t0 < t1当我们确定值的实际差异(溢出之前)不大于包含所有可能值的集合的一半或大小时,效果会更好。
对于纳秒,它将大约是 292 年(纳秒存储在 long 中,long大小的一半是2^64/2=2^63纳秒 ~= 292 年)。

因此,对于间隔少于 292 年的时间样本,我们应该使用它t0 - t1 < 0来获得正确的结果。


为了更好地可视化,可以说循环包含 8 个可能的值,它们是-4, -3, -2, -1 ,0, 1, 2, 3.

所以时间线看起来像

real time values:  .., -6, -5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5,  6,  7, ..
overflowed values: ..,  2,  3, -4, -3, -2, -1,  0,  1,  2,  3, -4, -3, -2, -1, ..

让我们看看差异将大于 4t0 - t1 < 0t0 < t1不会大于 4 的值(循环大小的一半,-4 是最小值,这意味着它可以是计算 delta 的最小结果)。请注意,只有在溢出t0 - t1 < 0时才会给出正确的结果t1

  1. delta = 1具有较大值的溢出注意:我们不会使较小的值溢出,因为这意味着这两个值都在同一个周期中,因此计算将与没有溢出一样)

    • 实际值:t0 = 3 t1 = 4
    • 溢出: t0 = 3 t1 = -4
    • t0 < t1==> 3 < -4 ->假的
    • t0 - t1 < 0==> 3 - (-4) < 0==> -1 < 0(7 溢出到 -1) true

    因此,尽管或者可能由于溢出,t0 - t1 < 0我们还是得到了正确的结果。

  2. delta = 1但这次没有溢出

    a) 正值

    • t0 = 2,t1 = 3
    • 2 < 3 真的
    • 2 - 3 < 0==>-1 < 0

    b) 负值

    • t0 = -4,t1 = -3
    • -4 < -3 真的
    • -4 - (-3) < 0==>-1 < 0

    对于其他实际 delta = 1 的情况,我们还将获得正确的结果t0 < t1t0 - t1 < 0测试(t0 - t1将始终如此-1

  3. delta = 3(几乎是周期的一半)

    a1) 具有较大值的溢出

    • 实际值:t0 = 3 t1 = 6
    • 溢出: t0 = 3 t1 = -2
    • t0 < t1==> 3 < -2 ->假的
    • t0 - t1 < 0==> 3 - (-2) < 0==> -3 < 0(5 溢出到 -3) true

    a2) 另一种溢出情况

    • 实际值:t0 = 2 t1 = 5
    • 溢出: t0 = 2 t1 = -3
    • t0 < t1==> 2 < -3 ->假的
    • t0 - t1 < 0==> 2 - (-3) < 0==> -3 < 0(再次 5 溢出到 -3)


    所以再次只t0 - t1 < 0给出了正确的结果。

    b)没有溢出 t0 - t1将始终等于-3(-delta),因此这将始终给出正确的结果。t0 < t1也会给出正确的resilt

    • 实际值:t0 = -1 t1 = 2
    • t0 < t1==> -1 < 2 ->
    • t0 - t1 < 0==> -1 - 2 < 0==>-3 < 0 真的
  4. delta = 4结果t0 - t1总是等于-4所以它也将是<0

    溢出示例
    a1)

    • 实际值:t0 = 0 t1 = 4
    • 溢出: t0 = 0 t1 = -4
    • t0 < t1==> 0 < -4 ->假的
    • t0 - t1 < 0==> 0 - (-4) < 0==> -4 < 0(4 溢出到 -4) true

    a2)

    • 实际值:t0 = 1 t1 = 5
    • 溢出: t0 = 1 t1 = -3
    • t0 < t1==> 1 < -4 ->假的
    • t0 - t1 < 0==> 1 - (-3) < 0==> -4 < 0(4 溢出到 -4) true

    所以再次只t0 - t1 < 0给出正确的结果。

    显然,没有溢出的示例对于这两个测试都是正确的。

  5. delta = 5(及更多)

    a1) 溢出
    (最小值 tor t0 是 -1,所以让我们从它开始)

    • 实际值:t0 = -1 t1 = 4
    • 溢出: t0 = -1 t1 = -4
    • t0 < t1==> -1 < -4 ->假的
    • t0 - t1 < 0==> -1 - (-4) < 0==>3 < 0 假的

    a2) 有溢出

    • 实际值:t0 = 1 t1 = 6
    • 溢出: t0 = 1 t1 = -2
    • t0 < t1==> 1 < -2 ->假的
    • t0 - t1 < 0==> 1 - (-2) < 0==> 3 < 0 false 两个测试都失败了

    b1) 无溢出

    • t0 = -4,t1 = 1
    • -4 < 1 真的
    • -4 - 1 < 0==> 3 < 0(-5 溢出到 3) false

+-------------+-----------------------------+----------------------------+
|  tests if   | delta <= size of half cycle | delta > size of half cycle |
| t0 is less  |-----------------------------|----------------------------|
|  than t1    |  overflow  |  no overflow   | overflow  |  no overflow   |
|-------------|------------|----------------|-----------|----------------|
|   t0 < t1   |      -     |       +        |     -     |       +        |
|-------------|------------|----------------|-----------|----------------|
| t0 - t1 < 0 |      +     |       +        |     -     |       +        |
|-------------|------------|----------------|-----------|----------------|
| t0 - t1 > 0 |      -     |       -        |     +     |       -        |
+-------------+------------+----------------+-----------+----------------+
于 2013-08-24T05:59:19.753 回答
1

API的引用实际上是:

由于数值溢出,超过大约 292 年(2^63 纳秒)的连续调用的差异将无法准确计算经过的时间。

如果 t0 和 t1 相隔 292 年测量,您将遇到数值溢出。否则,比较或减法都可以正常工作。

于 2013-08-24T02:04:31.067 回答
-1

使用任何方法。
在最近的 290 年内不会有什么不同。
您的程序(甚至 Java 本身)不会存在这么久。

于 2013-08-24T05:30:44.463 回答