From mu@che|||j2 @end|ng |rom gm@||@com  Thu Mar  3 18:22:32 2022
From: mu@che|||j2 @end|ng |rom gm@||@com (John Muschelli)
Date: Thu, 3 Mar 2022 12:22:32 -0500
Subject: [Rd] Floating Point with POSIXct
In-Reply-To: <25120.62040.753761.512280@stat.math.ethz.ch>
References: <CAFsq6G_cp=6pyh7CEe=rLUK47i+9LqtTyyK5zwjsdcNKnVigVg@mail.gmail.com>
 <25120.62040.753761.512280@stat.math.ethz.ch>
Message-ID: <CAFsq6G_va8iJSgY4pmp=xESMmxg4WX8+6fSabqUEDVTVObvphQ@mail.gmail.com>

Martin - I agree that the floating point representation of 0.025 is a
piece of the puzzle, but yes the heart was whether format/%OS3 should
potentially round vs. truncate.  As it's spelled out in ?strptime that
it will truncate, there is no bug per se, but simply unexpected
behavior and I wanted to know if that was the intent in this case.
Best,
John

On Thu, Mar 3, 2022 at 11:52 AM Martin Maechler
<maechler at stat.math.ethz.ch> wrote:
>
> >>>>> 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 at r-project.org mailing list
>     > https://stat.ethz.ch/mailman/listinfo/r-devel



[Rd] Floating Point with POSIXct
John Muschelli