[R] Floating point precision causing undesireable behaviour when printing as.POSIXlt times with microseconds?

Jim Holtman jholtman at gmail.com
Thu Apr 25 11:25:02 CEST 2013


FAQ 7.31

also if you are using POSIXct for current dates, the resolution is down to about a milliseconds.

Sent from my iPad

On Apr 24, 2013, at 13:57, "O'Hanlon, Simon J" <simon.ohanlon at imperial.ac.uk> wrote:

> Dear list,
> When using as.POSIXlt with times measured down to microseconds the default format.POSIXlt seems to cause some possibly undesirable behaviour:
> 
> According to the code in format.POSIXlt the maximum accuracy of printing fractional seconds is 1 microsecond, but if I do;
> 
> options( digits.secs = 6 )
> as.POSIXlt( 1.000002 , tz="", origin="1970-01-01")
> as.POSIXlt( 1.999998 , tz="", origin="1970-01-01")
> as.POSIXlt( 1.999999 , tz="", origin="1970-01-01")
> 
> I return respectively:
> [1] "1970-01-01 01:00:01.000002 BST"
> [1] "1970-01-01 01:00:01.999998 BST"
> [1] "1970-01-01 01:00:01 BST"
> 
> If options( digits.secs = 6 ) should I not expect to be able to print 1.999999 seconds? This seems to be caused by the following code fragment in format.POSIXlt:
> 
> np <- getOption("digits.secs")
>        if (is.null(np))
>            np <- 0L
>        else np <- min(6L, np)
>        if (np >= 1L)
>            for (i in seq_len(np) - 1L) if (all(abs(secs - round(secs,
>                i)) < 1e-06)) {
>                np <- i
>                break
>            }
> 
> Specifically
>            for (i in seq_len(np) - 1L) if (all(abs(secs - round(secs,
>                i)) < 1e-06))
> Which in the case of 1.999999 seconds will give:
> 
> options( scipen = 10 )
> np <- 6
> sapply( seq_len(np) - 1L , function(x) abs(1.999999 - round(1.999999, x)) )
> 
>         [,1]     [,2]     [,3]     [,4]     [,5]     [,6]
> [1,] 0.000001 0.000001 0.000001 0.000001 0.000001 0.000001
> 
> The logical test all( ... < 1e-06)  should evaluate to FALSE but due to floating point precision it evaluates TRUE:
> 
> sprintf( "%.20f" , abs(1. 999999  - round(1. 999999,5)))
> [1] "0.00000099999999991773"
> 
> If instead of:
> 
>            for (i in seq_len(np) - 1L) if (all(abs(secs - round(secs,
>                i)) < 1e-06))
> 
> in format.POSIXlt we had a comparison value that was half the minimum increment:
> 
>            for (i in seq_len(np) - 1L) if (all(abs(secs - round(secs,
>                i)) < 5e-07))
> 
> This behaviour disappears:
> 
> mod.format.POSIXlt( as.POSIXlt( 1.999999 , tz="", origin="1970-01-01") )
> [1] "1970-01-01 01:00:01.999999"
> 
> But I am unsure if the original behaviour is what I should expect given the documentation (I have read it and I can't see a reason to expect 1.999999 to round down to 1). And also if changing the formatting function would have other undesirable consequences?
> 
> My sessionInfo():
> R version 3.0.0 (2013-04-03)
> Platform: x86_64-w64-mingw32/x64 (64-bit)
> 
> locale:
> [1] LC_COLLATE=English_United Kingdom.1252
> [2] LC_CTYPE=English_United Kingdom.1252
> [3] LC_MONETARY=English_United Kingdom.1252
> [4] LC_NUMERIC=C
> [5] LC_TIME=English_United Kingdom.1252
> 
> attached base packages:
> [1] stats     graphics  grDevices utils     datasets  methods   base
> 
> 
> 
> Thank you,
> 
> 
> Simon
> 
> 
> ------------------------------------
> Simon O'Hanlon
> Postgraduate Researcher
> 
> Helminth Ecology Research Group
> Department of Infectious Disease Epidemiology
> Imperial College London
> St. Mary's Hospital, Norfolk Place,
> London, W2 1PG, UK
> 
> Office: +44 (0) 20 759 43229
> ------------------------------------
> 
> 
>    [[alternative HTML version deleted]]
> 
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.



More information about the R-help mailing list