как безопасно хранить миллисекундные различия между временными метками? - PullRequest
0 голосов
/ 05 марта 2020

Это какой-то хелли sh вопрос, связанный с аппроксимациями с плавающей точкой и временными метками в R. Приготовьтесь :) Рассмотрим простой пример:

library(tibble)
library(lubridate)
library(dplyr)

tibble(timestamp_chr1 = c('2014-01-02 01:35:50.858'),
       timestamp_chr2 = c('2014-01-02 01:35:50.800')) %>% 
  mutate(time1 = lubridate::ymd_hms(timestamp_chr1),
         time2 = lubridate::ymd_hms(timestamp_chr2),
         timediff = as.numeric(time1 - time2))


# A tibble: 1 x 5
  timestamp_chr1          timestamp_chr2          time1                      time2                       timediff
  <chr>                   <chr>                   <dttm>                     <dttm>                         <dbl>
1 2014-01-02 01:35:50.858 2014-01-02 01:35:50.800 2014-01-02 01:35:50.858000 2014-01-02 01:35:50.799999 0.0580001

Здесь разница во времени между двумя временными метками очевидна 58 миллисекунды, но R сохраняет это с некоторым приближением с плавающей точкой, так что оно выглядит как 0.058001 секунд.

Какой самый безопасный способ получить точно 58 миллисекунд как вместо ответа? Я думал об использовании as.integer (вместо as.numeric), но меня беспокоит некоторая потеря информации. Что тут можно сделать?

Спасибо!

1 Ответ

1 голос
/ 06 марта 2020

Некоторые соображения, некоторые, я думаю, вы уже знаете:

  • с плавающей точкой редко даст вам идеально 58 миллисекунд (из-за R FAQ 7.31 и IEEE- 754);

  • отображение данных может управляться на консоли с помощью options(digits.secs=3)digits=3) и в отчетах с sprintf, format или round;

  • расчет"доброта" может быть улучшена, если вы округлите до расчета; хотя это немного более обременительно, поскольку мы можем с уверенностью предположить, что данные точны по крайней мере до миллисекунд, это верно математически.

Если вы обеспокоены ошибками в Данные, однако, альтернатива заключается в кодировании в миллисекундах (вместо R нормы секунд). Если вы можете выбрать произвольную и недавнюю (до 24 дней) контрольную точку, то вы можете сделать это с помощью обычной integer, но если этого недостаточно или вы предпочитаете использовать epoch миллисекунд , то вам необходимо перейти к 64-битным целым числам, возможно с bit64.

now <- Sys.time()
as.integer(now)
# [1] 1583507603
as.integer(as.numeric(now) * 1000)
# Warning: NAs introduced by coercion to integer range
# [1] NA
bit64::as.integer64(as.numeric(now) * 1000)
# integer64
# [1] 1583507603439
...