Why should I use t1 - t0 < 0, not t1 < t0, when using System.nanoTime() in Java
t0 - t1 < 0
is better then t0 < t1
when we are sure that real difference of values (before overflow) is not grater than half or size of set that contains all possible values.
For nanoseconds it will be approximately 292 years (nanoseconds are stored in long and half of long
size is 2^64/2
= 2^63
nanoseconds ~= 292 years).
So for time samples separated with less then 292 years we should use t0 - t1 < 0
to get correct results.
To better visualize it lets say that cycle contains 8 possible values which are -4, -3, -2, -1 ,0, 1, 2, 3
.
So timeline can look like
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, ..
Lets take a look how t0 - t1 < 0
and t0 < t1
will behave for values where difference will be and wont be greater than 4 (half of cycle size, and -4 is minimal value which means it can be minimal result for calculating delta). Notice that only t0 - t1 < 0
will give correct results when t1
overflows
delta = 1 with overflow of bigger value (notice: we don't make lesser value overflow because it would mean that both values are in the same cycle so calculations would be same as if there wouldn't be any overflow)
- real values:
t0 = 3
t1 = 4
- overflowed:
t0 = 3
t1 = -4
t0 < t1
==>3 < -4
-> falset0 - t1 < 0
==>3 - (-4) < 0
==>-1 < 0
(7 overflows to -1) true
so only for
t0 - t1 < 0
we got correct result despite or maybe thanks to overflow.- real values:
delta = 1 but this time no overflow
a) positive values
t0 = 2
,t1 = 3
2 < 3
true2 - 3 < 0
==>-1 < 0
true
b) negative values
t0 = -4
,t1 = -3
-4 < -3
true-4 - (-3) < 0
==>-1 < 0
true
for rest of cases where real delta = 1 we will also get correct results for both
t0 < t1
andt0 - t1 < 0
tests (t0 - t1
will be always-1
)delta = 3 (almost half of cycle)
a1) with overflow of bigger value
- real values:
t0 = 3
t1 = 6
- overflowed:
t0 = 3
t1 = -2
t0 < t1
==>3 < -2
-> falset0 - t1 < 0
==>3 - (-2) < 0
==>-3 < 0
(5 overflows to -3) true
a2) another case with overflow
- real values:
t0 = 2
t1 = 5
- overflowed:
t0 = 2
t1 = -3
t0 < t1
==>2 < -3
-> falset0 - t1 < 0
==>2 - (-3) < 0
==>-3 < 0
(again 5 overflows to -3) true
So again onlyt0 - t1 < 0
gave correct result.b) without overflow
t0 - t1
will always be equal to-3
(-delta) so this will always be giving correct result.t0 < t1
will also give correct resilt- real values:
t0 = -1
t1 = 2
t0 < t1
==>-1 < 2
-> truet0 - t1 < 0
==>-1 - 2 < 0
==>-3 < 0
true
- real values:
delta = 4 result of
t0 - t1
will always be equal to-4
so it will also be<0
.examples with overflow
a1)- real values:
t0 = 0
t1 = 4
- overflowed:
t0 = 0
t1 = -4
t0 < t1
==>0 < -4
-> falset0 - t1 < 0
==>0 - (-4) < 0
==>-4 < 0
(4 overflows to -4) true
a2)
- real values:
t0 = 1
t1 = 5
- overflowed:
t0 = 1
t1 = -3
t0 < t1
==>1 < -4
-> falset0 - t1 < 0
==>1 - (-3) < 0
==>-4 < 0
(4 overflows to -4) true
So again only
t0 - t1 < 0
give correct results.Examples without overflow obviously will be correct for both tests.
- real values:
delta = 5 (and more)
a1) with overflow
(minimal value tor t0 is -1 so lets start with it)- real values:
t0 = -1
t1 = 4
- overflowed:
t0 = -1
t1 = -4
t0 < t1
==>-1 < -4
-> falset0 - t1 < 0
==>-1 - (-4) < 0
==>3 < 0
false
a2) with overflow
- real values:
t0 = 1
t1 = 6
- overflowed:
t0 = 1
t1 = -2
t0 < t1
==>1 < -2
-> falset0 - t1 < 0
==>1 - (-2) < 0
==>3 < 0
false both tests failed
b1) without overflow
t0 = -4
,t1 = 1
-4 < 1
true-4 - 1 < 0
==>3 < 0
(-5 overflows to 3) false
- real values:
+-------------+-----------------------------+----------------------------+
| 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 | - | - | + | - |
+-------------+------------+----------------+-----------+----------------+
The quote from the API is actually:
Differences in successive calls that span greater than approximately 292 years (2^63 nanoseconds) will not accurately compute elapsed time due to numerical overflow.
If t0 and t1 are measured 292 years apart you will experience numerical overflow. Otherwise either the comparison or the subtraction will work just fine.
The Nano time is not a 'real' time, it is just a counter that increments starting from some unspecified number when some unspecified event occurs (maybe the computer is booted up).
It will overflow, and become negative at some point. If your t0
is just before it overflows (i.e. very large positive), and your t1
is just after (very large negative number), then t1 < t0
(i.e. your conditions are wrong because t1
happened after t0
).....
But, if you say t1 - t0 < 0
, well, the magic is that a for the same overflow (undeflow) reasons (very large negative subtract a very large positive will underflow), the result will be the number of nanoseconds that t1 was after t0
..... and will be right.
In this case, two wrongs really do make a right!