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

时间:2013-08-24 01:34:46

标签: java math comparison overflow

当我在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() - why use comparison vs. subtraction?

这两件事情是矛盾的。

4 个答案:

答案 0 :(得分:13)

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

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

之后

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

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

答案 1 :(得分:8)

当我们确定 实际 值的差异(溢出前)不大于一半或大小时,

t0 - t1 < 0优于t0 < t1包含所有可能值的集合 对于纳秒,它将大约为292年(纳秒存储为长,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, ..

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

  1. delta = 1 溢出更大的价值(通知:我们不会让价值减少,因为它意味着两个值都处于同一个周期,因此计算就像没有任何溢出一样)

    • 真实值:t0 = 3 t1 = 4
    • 溢出:t0 = 3 t1 = -4
    • t0 < t1 ==&gt; 3 < -4 - &gt;的
    • t0 - t1 < 0 ==&gt; 3 - (-4) < 0 ==&gt; -1 < 0(7溢出到-1) true

    所以只有t0 - t1 < 0我们得到了正确的结果尽管或者感谢溢出。

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

    a)正值

    • t0 = 2t1 = 3
    • 2 < 3 true
    • 2 - 3 < 0 ==&gt; -1 < 0 true

    b)负值

    • t0 = -4t1 = -3
    • -4 < -3 true
    • -4 - (-3) < 0 ==&gt; -1 < 0 true

    对于其中实际delta = 1的其他情况,我们也会得到t0 < t1t0 - t1 < 0测试的正确结果(t0 - t1将始终为-1

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

    a1)溢出更大的值

    • 真实值:t0 = 3 t1 = 6
    • 溢出:t0 = 3 t1 = -2
    • t0 < t1 ==&gt; 3 < -2 - &gt;的
    • t0 - t1 < 0 ==&gt; 3 - (-2) < 0 ==&gt; -3 < 0(5溢出至-3) true

    a2)溢出

    的另一个案例
    • 真实值:t0 = 2 t1 = 5
    • 溢出:t0 = 2 t1 = -3
    • t0 < t1 ==&gt; 2 < -3 - &gt;的
    • t0 - t1 < 0 ==&gt; 2 - (-3) < 0 ==&gt; -3 < 0(再次5溢出到-3) true


    所以只有t0 - t1 < 0才能给出正确的结果。

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

    • 真实值:t0 = -1 t1 = 2
    • t0 < t1 ==&gt; -1 < 2 - &gt;的
    • t0 - t1 < 0 ==&gt; -1 - 2 < 0 ==&gt; -3 < 0 true
  4. delta = 4 t0 - t1的结果将始终等于-4,因此它也将是<0

    示例溢出
    a1)的

    • 真实值:t0 = 0 t1 = 4
    • 溢出:t0 = 0 t1 = -4
    • t0 < t1 ==&gt; 0 < -4 - &gt;的
    • t0 - t1 < 0 ==&gt; 0 - (-4) < 0 ==&gt; -4 < 0(4溢出至-4) true

    a2)

    • 真实值:t0 = 1 t1 = 5
    • 溢出:t0 = 1 t1 = -3
    • t0 < t1 ==&gt; 1 < -4 - &gt;的
    • t0 - t1 < 0 ==&gt; 1 - (-3) < 0 ==&gt; -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 ==&gt; -1 < -4 - &gt;的
    • t0 - t1 < 0 ==&gt; -1 - (-4) < 0 ==&gt; 3 < 0 false

    a2)溢出

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

    b1)没有溢出

    • t0 = -4t1 = 1
    • -4 < 1 true
    • -4 - 1 < 0 ==&gt; 3 < 0(-5溢出至3) false

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

答案 2 :(得分:1)

API的引用实际上是:

  

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

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

答案 3 :(得分:-1)

使用任何方法。
在最近的290年内没有区别 你的程序(甚至Java本身)将不会存在这么久。