Точность против точности System.nanoTime()
Документация для System.nanoTime()
говорит следующее (выделение мое).
Этот метод может использоваться только для измерения прошедшего времени и не связан с каким-либо другим понятием системного или настенного времени. Возвращаемое значение представляет наносекунды с некоторого фиксированного, но произвольного времени (возможно, в будущем, поэтому значения могут быть отрицательными). Этот метод обеспечивает точность наносекунды, но не обязательно точность наносекунды. Не делается никаких гарантий относительно того, как часто меняются значения.
На мой взгляд, это можно интерпретировать двумя разными способами:
Предложение, выделенное жирным шрифтом выше, относится к отдельным возвращаемым значениям. Тогда точность и аккуратность следует понимать в числовом смысле. То есть точность относится к числу значащих цифр - позиции усечения, а точность - к правильному числу (как описано в верхнем ответе здесь. В чем разница между "точностью" и "точностью"?)
Предложение, выделенное жирным шрифтом выше, относится к возможностям самого метода. Затем следует понимать точность и точность, как показано на аналогии с дартс ( http://en.wikipedia.org/wiki/Precision_vs._accuracy). Таким образом, низкая точность, высокая точность => неправильное значение многократно повторяется с высокой точностью: воображая, что физическое время останавливается, последовательные вызовы nanoTime() возвращают одно и то же числовое значение, но оно не соответствует фактическому истекшему времени, так как эталонное время на некоторое постоянное смещение.
Какая интерпретация является правильной? Моя точка зрения заключается в том, что интерпретация 2 будет означать, что мера разницы во времени с использованием nanoTime() (путем вычитания двух возвращаемых значений) будет правильной с точностью до наносекунды (поскольку постоянная ошибка / смещение в измерении будет устранена), тогда как интерпретация 1 будет не гарантирует такого соответствия между измерениями и, следовательно, не обязательно подразумевает высокую точность измерений разницы во времени.
Обновлено 15.04.13: документация по Java 7 для System.nanoTime()
был обновлен для устранения возможной путаницы с предыдущей формулировкой.
Возвращает текущее значение источника времени работающей виртуальной машины Java с высоким разрешением в наносекундах.
Этот метод может использоваться только для измерения прошедшего времени и не связан с каким-либо другим понятием системного или настенного времени. Возвращаемое значение представляет наносекунды с некоторого фиксированного, но произвольного времени начала (возможно, в будущем, поэтому значения могут быть отрицательными). Один и тот же источник используется всеми вызовами этого метода в экземпляре виртуальной машины Java; другие экземпляры виртуальной машины могут использовать другое происхождение.
Этот метод обеспечивает точность наносекунды, но не обязательно наносекундное разрешение (то есть как часто изменяется значение) - никаких гарантий не предоставляется, за исключением того, что разрешение, по крайней мере, такое же, как и у
currentTimeMillis()
,Различия в последовательных вызовах, которые охватывают более чем приблизительно 292 года (2 63 наносекунды), не будут правильно вычислять истекшее время из-за числового переполнения.
Значения, возвращаемые этим методом, становятся значимыми, только когда вычисляется разница между двумя такими значениями, полученными в одном и том же экземпляре виртуальной машины Java.
4 ответа
Первая интерпретация верна. В большинстве систем три младшие цифры всегда будут равны нулю. Это в действительности дает микросекундную точность, но сообщает об этом с фиксированным уровнем точности наносекунды.
Фактически, теперь, когда я смотрю на это снова, ваша вторая интерпретация также является достоверным описанием того, что происходит, может быть, даже более того. Представляя замерзшее время, отчет всегда будет иметь одинаковое неправильное количество наносекунд, но будет правильным, если понимать его как целое число микросекунд.
В командной строке Clojure я получаю:
user=> (- (System/nanoTime) (System/nanoTime))
0
user=> (- (System/nanoTime) (System/nanoTime))
0
user=> (- (System/nanoTime) (System/nanoTime))
-641
user=> (- (System/nanoTime) (System/nanoTime))
0
user=> (- (System/nanoTime) (System/nanoTime))
-642
user=> (- (System/nanoTime) (System/nanoTime))
-641
user=> (- (System/nanoTime) (System/nanoTime))
-641
По сути, nanoTime
не обновляется каждую наносекунду, вопреки тому, что можно интуитивно ожидать от его точности. В системах Windows он использует QueryPerformanceCounter
API под капотом (согласно этой статье), который на практике, похоже, дает разрешение около 640 нс (в моей системе!).
Обратите внимание, что nanoTime
сама по себе не может иметь никакой точности, поскольку ее абсолютное значение произвольно. Только разница между последовательными nanoTime
звонки имеет смысл. Точность (в) этой разницы находится в приблизительном интервале в 1 микросекунду.
Одна довольно интересная особенность различия между System.currentTimeMillis()
& System.nanoTime()
в том, что System.nanoTime()
НЕ меняется с настенными часами. Я запускаю код на виртуальной машине Windows, которая имеет значительный дрейф времени. System.currentTimeMillis()
может перемещаться назад или вперед на 1-2 секунды каждый раз, когда NTP исправляет этот дрейф, делая точные отметки времени бессмысленными. (Выпуски Windows 2003, VPS 2008)
System.nanoTime()
Однако на изменение времени настенных часов не влияет, так что вы можете использовать время, полученное через NTP, и применить коррекцию на основе System.nanoTime()
так как NTP был проверен в последний раз, и у вас гораздо более точное время, чем System.currentTimeMillis()
в неблагоприятных условиях настенных часов
Это, конечно, нелогично, но полезно знать
Если кто-то, как я, приходит и читает этот вопрос снова и снова и снова, чтобы все-таки понять его, вот более простое (я надеюсь) объяснение.
Precision
о том, сколько цифр вы сохраняете. Каждый из:
long start = System.nanoTime();
long end = System.nanoTime();
будет точное число (много цифр).
поскольку accuracy
измеряется только по сравнению с чем-то, индивидуальный вызов System.nanoTime
не имеет смысла, так как его значение совершенно произвольно и не зависит от того, что мы можем измерить. Единственный способ отличить его точность - это два разных вызова, таким образом:
long howMuch = end - start;
не будет иметь точность с точностью до наносекунды. А на самом деле на моей машине разница составляет 0,2 - 0,3 микросекунды.