Как сравнить два значения времени nano? [javadoc confusion]
Я прочитал javadoc для System.nanoTime()
, и все это кажется ясным. Пока я не дошел до финального абзаца:
Чтобы сравнить два значения nanoTime
long t0 = System.nanoTime();
...
long t1 = System.nanoTime();
следует использовать t1 - t0 < 0, а не t1 < t0, из-за возможности численного переполнения.
Есть две вещи, которые мне непонятно:
- Почему бы проверить, если
t1 < t0
, если t1
было взято после t0
? Я понимаю, что нано-время всегда увеличивается. Итак, я бы предпочел проверить t1 > t0
.
- Предположим, что опечатка, и они означали правильную проверку
t1 - t0 > 0
. Я до сих пор не понимаю, почему это правильный способ проверки, а не t1 > t0
. Они упоминают численное переполнение, и я не совсем понимаю, что они означают. Что касается численного переполнения, здесь упоминается следующее:
Различия в последовательных вызовах, которые охватывают более 292 лет (2 ^ 63 наносекунды), не будут правильно вычислять прошедшее время из-за численного переполнения.
ОК, поэтому, поскольку нано-время хранится как длинное значение, оно в конечном итоге переполняется через 292 года. И что будет дальше? Началось ли это с самого начала, т.е. Самое низкое отрицательное значение -2 ^ 63? Или он всегда останавливает измерение и возвращает (2 ^ 63 - 1)?
Ответы
Ответ 1
Вы правы, части документации, которые вы цитировали, немного запутались.
Однако часть документации, которая имеет значение, такова:
Этот метод может использоваться только для измерения прошедшего времени и не имеет отношения к какому-либо другому понятию системного или настенного времени. Возвращаемое значение представляет собой наносекунды с некоторого фиксированного, но произвольного времени начала (возможно, в будущем, поэтому значения могут быть отрицательными). Такое же происхождение используется всеми вызовами этого метода в экземпляре виртуальной машины Java; другие экземпляры виртуальной машины могут использовать другое происхождение.
(выделено мной мной.)
Это означает, что у вас нет никаких гарантий того, что ваш код не будет работать в то время, когда полученное длинное значение произойдет с переводом с положительного на отрицательный.
Нет ничего, что гарантировало бы, что это произойдет через 300 лет, это может произойти сегодня.
В настоящее время моя JVM возвращает некоторое число, например 3496793269188, но если бы оно захотелось, было бы возвращено некоторое число, очень близкое к 9223372036854775807 (это Long.MAX_VALUE
), которое сделало бы переворот с положительного на отрицательный.
Итак, вы должны принять все необходимые меры предосторожности.
Ответ 2
Ну, javadoc
говорит правду. Рассмотрим такой пример:
long t0 = Long.MAX_VALUE;
long t1 = Long.MIN_VALUE;
System.out.println(t1 < t0);
System.out.println(t1 - t0 < 0);
Он даст
true
false
тогда как математически оба выражения истинны. Но в нашем случае мы знаем, что отрицательное значение time
означает, что оно переполнено, следовательно, оно должно быть действительно большим, чем положительное число.
Ответ 3
Позвольте мне начать с конца вашего вопроса. Да в случае, если значение больше 2 ^ 63-1, значение будет переполняться. Общая реализация переполнения заключается в том, что сохраняются наименее значимые представляемые биты результата; значение будет wrap (вы можете увидеть в нижней части моего сообщения о переполнении для справки)
Последовательность: 2^63-2, 2^63-1, -2^63, -(2^63-1) ...
Теперь, оглядываясь назад на Javadoc, я согласен с тем, что объяснение использования сравнения путается, и, естественно, мы попытаемся сравнить t1 > t0
, чтобы проверить, произошло ли t1
после t0
. Вы частично правы. Хотя я не думаю, что это опечатка, но она не объясняется правильно. Я думаю, он должен сказать:
Для двух значений t0
и t1
(где t1 захватывается после t0), вы не должны использовать t1 < t0
(для проверки false
), а скорее t1 - t0 < 0
, аналогично вам не следует использовать t1 > t0
(для проверки true
), но скорее t1 - t0 > 0
Или для его формализации:
Для двух значений "nano" t0
и t1
, где t1
захватывается после t0
следующих таблиц: (t1 - t0 > 0) == true
, пока период между t1
и t0
составляет <= 2 ^ 63 нс.
Почему? Поскольку даже когда t1
переполняется (поэтому он отрицательный), результат t1 - t0
также будет отрицательным , но он будет меньше -2 ^ 64, и он будет "переполняться назад" до положительного значения!.
Это стоит, пока выполняется условие о расстоянии между t0
и t1
! В случае, если расстояние больше 2 ^ 64, например: для t0 = 1; t1 = -(2^64-2)
, результат вычитания будет: t1 - t0 = -(2^64-1)
, поэтому указанное условие (t1 - t0 > 0
) даст неверный результат.
Right:)
При переполнении
Для объяснения lats принимает тип, который хранится с использованием 8 бит (вместо 64 используется длинным), поэтому двоичное до десятичного представления:
0000 0000 => 0
0000 0001 => 1 (2^0)
0000 0010 => 2 (2^1 + 2^0)
...
1111 1111 => 255 (2^7 + 2^6 + ... + 2^1)
теперь следующее число естественно, если вы увеличите на 1.
добавление 1 к двоичному 1111 1111 приведет к созданию 1 0000 0000
(1) 0000 0000 => -256 !!!
обычно бит переполнения в позиции 8 будет представлять знаковый бит (отрицательный вес)
first following value is adding 1 to most-right position
(1) 0000 0001 => -256 + 2^0 = -255
(1) 0000 0010 => -256 + 2^1 = -254
(1) 0000 0011 => -256 + 2^1 + 2^1 = -253
...
вы получите изображение
Источником этого является реализация основного реестра оборудования, которая основывается на двоичных значениях.
Здесь вы можете прочитать более подробное объяснение: http://www.allaboutcircuits.com/textbook/digital/chpt-2/binary-overflow/
Ответ 4
Когда t1 берется после t0 (t1 < t0 = false в реальном слове), и есть поток owerflow для t1 (не t0). t1 отрицательно, и t0 положительный - это случай t1 - t0 < 0 дает вам хороший результат false, потому что двоичная операция "-" не допускает ошибки owerflow и t1 < t0 даст неверный результат: true
Более базовое отрицательное число, если оно читает беззнаковое число, больше, чем подписанное положительное число: https://en.wikipedia.org/wiki/Signed_number_representations и