为什么我应该在Java中使用System.nanoTime()时使用t1 - t0<0,而不是t1<t0

2022-09-02 10:21:42

当我在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() - 为什么使用比较与减法?

这两件事就自相矛盾了。


答案 1

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

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

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

在这种情况下,两个错误确实是正确的!


答案 2

t0 - t1 < 0当我们确定值的实际差值(溢出之前)不比包含所有可能值的集合的一半或大小更糟糕时,会更好。
对于纳秒,它将是大约292年(纳秒以长和一半的大小存储=纳秒〜= 292年)。t0 < t1long2^64/22^63

因此,对于间隔时间少于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, ..

让我们看一下对于差值将大于和不会大于4的值(周期大小的一半,-4是最小值,这意味着它可以是计算增量的最小结果)的行为方式和行为。请注意,仅当溢出时才会给出正确的结果t0 - t1 < 0t0 < t1t0 - t1 < 0t1

  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)

    所以只有我们得到了正确的结果,尽管或者可能要感谢溢出。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 < 0t0 - 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)

    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) 没有溢出将始终等于 (-delta),因此这将始终给出正确的结果。 也会给出正确的转印t0 - t1-3t0 < t1

    • 实际值: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)

    a2)

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

    因此,再次只给出正确的结果。t0 - t1 < 0

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

  5. 增量 = 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)

+-------------+-----------------------------+----------------------------+
|  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 |      -     |       -        |     +     |       -        |
+-------------+------------+----------------+-----------+----------------+

推荐