[Rd] Floating Point with POSIXct
Martin Maechler
m@ech|er @end|ng |rom @t@t@m@th@ethz@ch
Thu Mar 3 17:52:40 CET 2022
>>>>> John Muschelli
>>>>> on Thu, 3 Mar 2022 11:04:05 -0500 writes:
>>>>> John Muschelli
>>>>> on Thu, 3 Mar 2022 11:04:05 -0500 writes:
> I see in ?POSIXct and I'm trying to understand the note:
>> Classes "POSIXct" and "POSIXlt" are able to express fractions of a second. (Conversion of fractions between the two forms may not be exact, but will have better than microsecond accuracy.)
> Mainly, I'm trying to understand printing of POSIXct with fractional
> seconds. I see print.POSIXct calls format.POSIXct and eventually
> calls format.POSIXlt, which then takes into account `digits.secs` for
> printing. The format uses %OS3, which strptime indicates (* added):
>> Specific to R is %OSn, which for output gives the seconds *truncated* to 0 <= n <= 6 decimal places (and if %OS is not followed by a digit, it uses the setting of getOption("digits.secs"), or if that is unset, n = 0).
> So I'm seeing it truncates the seconds to 3 digits, so I think that is
> why the below is printing 0.024.
> I think this is especially relevant even if you set
> `options(digits.secs = 6)`, then the code in
> format.POSIXlt would still return np=3 as the following condition
> would break at i = 3
> for (i in seq_len(np) - 1L)
> if (all(abs(secs - round(secs, > i)) < 1e-06)) {
> np <- i
> break
> }
> as sub_seconds - round(sub_seconds,3) < 1e-06. This seems to be
> expected behavior given the docs, but would any consider this a bug?
> Example:
> options(digits.secs = 4)
> x = structure(947016000.025, class = c("POSIXct", "POSIXt"), tzone = "UTC")
I think you've fallen into the R FAQ 7.31 trap :
> ct <- 947016000.025
> ct %% 1
[1] 0.02499998
>
Of course, the issue may still be somewhat interesting, ...
Yes, POSIXct is of limited precision and I think the help page
you mentioned did document that that's one reason for using
POSIXlt instead, as there, sub second accuracy can be much better.
But FAQ 7.31 and the fact that all numbers are base 2 and in
base 2, no decimal <n>.025 can be represented in full accuracy.
Also, as you've noticed the R POSIX[cl]t code just truncates,
i.e. rounds towards 0 unconditionally, and I tend to agree that it
should rather round than truncate.
But we should carefully separate the issues here, from the
underlying inherent FAQ 7.31 truth that most decimal numbers in
a computer are not quite what they look like ...
Martin Maechler
ETH Zurich and R Core Team (also author of the CRAN package 'round')
> summary(x, digits = 20)
> #> Min. 1st Qu. Median
> #> "2000-01-04 20:00:00.024" "2000-01-04 20:00:00.024" "2000-01-04 20:00:00.024"
> #> Mean 3rd Qu. Max.
> #> "2000-01-04 20:00:00.024" "2000-01-04 20:00:00.024" "2000-01-04 20:00:00.024"
> x
> #> [1] "2000-01-04 20:00:00.024 UTC"
> format.POSIXct(x, format = "%Y-%m-%d %H:%M:%OS3")
> #> [1] "2000-01-04 20:00:00.024"
> format.POSIXct(x, format = "%Y-%m-%d %H:%M:%OS4")
> #> [1] "2000-01-04 20:00:00.0249"
> sub_seconds = as.numeric(x) %% 1
> sub_seconds
> #> [1] 0.02499998
> round(sub_seconds, 3)
> #> [1] 0.025
> rounded = as.POSIXct(
> floor(as.numeric(x)) +
> round(as.numeric(x) %% 1, 3),
> origin = "1970-01-01")
> rounded
> #> [1] "2000-01-04 20:00:00.024 UTC"
> as.numeric(rounded) %% 1
> #> [1] 0.02499998
> R.version
> _
> platform x86_64-pc-linux-gnu
> arch x86_64
> os linux-gnu
> system x86_64, linux-gnu
> status
> major 4
> minor 1.2
> year 2021
> month 11
> day 01
> svn rev 81115
> language R
> version.string R version 4.1.2 (2021-11-01)
> nickname Bird Hippie
> Best,
> John
> ______________________________________________
> R-devel using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
More information about the R-devel
mailing list