当我在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 < B
比A - B < 0
更优先。
Java Integer compareTo() - why use comparison vs. subtraction?
这两件事情是矛盾的。
答案 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 < 0
和t0 < t1
将如何处理差值将不会大于4的值(循环大小的一半,-4是最小值,这意味着它可以是计算delta的最小结果)。请注意,t0 - t1 < 0
溢出时只有t1
才会显示正确的结果
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
我们得到了正确的结果尽管或者感谢溢出。
delta = 1 ,但这次没有溢出
a)正值
t0 = 2
,t1 = 3
2 < 3
true 2 - 3 < 0
==&gt; -1 < 0
true b)负值
t0 = -4
,t1 = -3
-4 < -3
true -4 - (-3) < 0
==&gt; -1 < 0
true 对于其中实际delta = 1的其他情况,我们也会得到t0 < t1
和t0 - t1 < 0
测试的正确结果(t0 - t1
将始终为-1
)
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 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
才会给出正确的结果。
没有溢出的例子显然对两个测试都是正确的。
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 = -4
,t1 = 1
-4 < 1
true -4 - 1 < 0
==&gt; 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 | - | - | + | - |
+-------------+------------+----------------+-----------+----------------+
答案 2 :(得分:1)
API的引用实际上是:
跨越大于约292年(2 ^ 63纳秒)的连续调用的差异将无法准确计算由于数值溢出而导致的经过时间。
如果t0和t1相隔292年测量,您将遇到数值溢出。否则比较或减法都可以正常工作。
答案 3 :(得分:-1)
使用任何方法。
在最近的290年内没有区别
你的程序(甚至Java本身)将不会存在这么久。