From m@ech|er @end|ng |rom @t@t@m@th@ethz@ch  Fri Mar 22 18:07:26 2019
From: m@ech|er @end|ng |rom @t@t@m@th@ethz@ch (Martin Maechler)
Date: Fri, 22 Mar 2019 18:07:26 +0100
Subject: [Rd] prettyNum digits=0 not compatible with scientific notation
In-Reply-To: <AAF25F95-1DDD-4C41-8132-54259D09679C@gmail.com>
References: <30D28A63376088428E8318DD67FD407FCADD67@ny-mailstore1.walleyetrading.net>
 <23700.42650.645514.620943@stat.math.ethz.ch>
 <AAF25F95-1DDD-4C41-8132-54259D09679C@gmail.com>
Message-ID: <23701.5710.730216.751381@stat.math.ethz.ch>

>>>>> peter dalgaard 
>>>>>     on Fri, 22 Mar 2019 17:30:19 +0100 writes:

    > FWIW, it doesn't seem to be happening on Mac OS:
    >> format(2^30, digits=0)
    > [1] "1.e+09"
    >> prettyNum(12345.6, digits=0)
    > [1] "1.e+04"

    > A glibc misfeature?

It seems (and note we are talking about format.default() here,
   	  of which prettyNum() is only a wrapper in this case):

Here's an example that shows that  'digits=0'  actually can make
"sense" contrary to what I've claimed previously::

nn <- 123456*10^(0:-8); dd <- c(10, 7, 2:0); names(dd) <- paste0("d=",dd)
sapply(dd, function(dig) sapply(nn, format, digits=dig))

gives (on Linux R 3.5.3, Fedora 28)

       d=10         d=7          d=2      d=1     d=0       
 [1,] "123456"     "123456"     "123456" "1e+05" "%#4.0-1e"
 [2,] "12345.6"    "12345.6"    "12346"  "12346" "%#4.0-1e"
 [3,] "1234.56"    "1234.56"    "1235"   "1235"  "1235"    
 [4,] "123.456"    "123.456"    "123"    "123"   "123"     
 [5,] "12.3456"    "12.3456"    "12"     "12"    "12"      
 [6,] "1.23456"    "1.23456"    "1.2"    "1"     "1"       
 [7,] "0.123456"   "0.123456"   "0.12"   "0.1"   "0"       
 [8,] "0.0123456"  "0.0123456"  "0.012"  "0.01"  "0"       
 [9,] "0.00123456" "0.00123456" "0.0012" "0.001" "0"       

but probably looks better on Mac

and on our  "Windows Server x64 (build 14393)",
		    for both Platforms
		 	i386-w64-mingw32/i386 (32-bit)
                       x86_64-w64-mingw32/x64 (64-bit)

is slightly "better":

      d=10         d=7          d=2      d=1     d=0
 [1,] "123456"     "123456"     "123456" "1e+05" "1.234560e+05"
 [2,] "12345.6"    "12345.6"    "12346"  "12346" "1.234560e+04"
 [3,] "1234.56"    "1234.56"    "1235"   "1235"  "1235"
 [4,] "123.456"    "123.456"    "123"    "123"   "123"
 [5,] "12.3456"    "12.3456"    "12"     "12"    "12"
 [6,] "1.23456"    "1.23456"    "1.2"    "1"     "1"
 [7,] "0.123456"   "0.123456"   "0.12"   "0.1"   "0"
 [8,] "0.0123456"  "0.0123456"  "0.012"  "0.01"  "0"
 [9,] "0.00123456" "0.00123456" "0.0012" "0.001" "0"

... interesting ...

Martin


    >> On 22 Mar 2019, at 10:10 , Martin Maechler <maechler at stat.math.ethz.ch> wrote:
    >> 
    >> Thank you, Robert for raising this here !
    >> 
    >>>>>>> Robert McGehee 
    >>>>>>> on Thu, 21 Mar 2019 20:56:19 +0000 writes:
    >> 
    >>> R developers,
    >>> Seems I get a bad result ("%#4.0-1e" in particular) when trying to use prettyNum digits=0 with scientific notation. I tried on both my Linux box and on an online R evaluator and saw the same problem, so it's not limited to my box at least. I see the problem in both R 3.5.3 and R 3.3.2.
    >> 
    >>> options(scipen= -100)
    >> 
    >> The above is extreme: You're basically setting an option to
    >> always see non-integer numbers in "scientific" format ..
    >> But read below about what 'digits' means in this case.
    >> 
    >>> prettyNum(1, digits=0)
    >>> [1] "%#4.0-1e"
    >>> prettyNum(2, digits=0)
    >>> [1] "%#4.0-1e"
    >>> prettyNum(1, digits=0, scientific=FALSE) # Works
    >>> [1] "1"
    >>> prettyNum(1:2, digits=0) # Works
    >>> [1] "1" "2"
    >>> prettyNum(c(1.1, 2.1), digits=0)
    >>> [1] "%#4.0-1e" "%#4.0-1e"
    >>> prettyNum(c(1.1, 2.1), digits=1) # Works
    >>> [1] "1e+00" "2e+00"
    >> 
    >> I'm the scape goat / culprit /.. : I have worked on tweaking the
    >> formatting of (non integer) numbers in R for a long time, on the
    >> way introducing prettyNum(), also already long ago...
    >> but then it's actually not prettyNum() but rather format() here :
    >> 
    >> Have you read its help page - *with* care?
    >> 
    >> If you do, you'd notice that 'digits' is not among the formal arguments
    >> of prettyNum() *and* that prettyNum() passes all its  `...`  to format().
    >> And if you read  ?format [which then you should to understand 'digits' !]
    >> you see
    >> 
    >>> digits: how many significant digits are to be used for numeric and
    >>> complex ?x?.  The default, NULL, uses ?getOption("digits")?.
    >>> This is a suggestion: enough decimal places will be used so that
    >>> the smallest (in magnitude) number has this many significant 
    >>> digits, and also to satisfy ?nsmall?.
    >> 
    >>> [.....]
    >> 
    >> So, for the real numbers you use in your example, digits are
    >> *significant* digits as in  'options(digits= *)' or
    >> 'print(.., digits= *)'
    >> 
    >> ------ Excursion about 'integer' and format()ing ------------
    >> -- and you now may also understand why   prettyNum(1:2, digits=0)  works
    >> as you expect: integer formatting behaves differently   ....
    >> but I acknowledge that the  ?format   help page does not say so
    >> explicitly yet:  it 'real and complex' numbers for the
    >> 'scientific' argument,  and 'numeric and complex' numbers for
    >> the 'format' argument.
    >> If you replac numeric by reald, what this entails (by logic)
    >> that 'integer' numbers are *not* affected by 'digits' nor  'scientific'.
    >> 
    >> But there's yet more subtlety: 'integer' here means class/type "integer"
    >> and not just an integer number, i.e., the difference of  1L and 1 :
    >> 
    >>> str(1)
    >> num 1
    >>> str(1L)
    >> int 1
    >>> str(1:3)
    >> int [1:3] 1 2 3
    >>> str(1:3 + 0)
    >> num [1:3] 1 2 3
    >>> 
    >> ------ end of Excursion{'integer' ..} -------------------------------
    >> 
    >> Back to real numbers : 'digits' are used as *significant* digits
    >> (and are only a suggestion: format() and prettyNum() ensure
    >> a common width for their resulting strings so printing will be
    >> nicely aligned), see e.g.
    >> 
    >>> format(3.14, scientific=FALSE)
    >> [1] "3.14"
    >>> format(3.14*c(1, 1e-7),   scientific=FALSE)
    >> [1] "3.140000000" "0.000000314"
    >>> 
    >> 
    >> So back to your examples : What would you mean with
    >> ``0 significant digits'' ? 
    >> It really does not make sense to show *no* significant digits ..
    >> 
    >> Intuitively, without spending enough time, I'd say that the bug
    >> in format.default() -- which is called by prettyNum() in
    >> this case -- is that it does *not* treat
    >> 'digits = 0'  as 'digits = 1'  in this case.  
    >> 
    >> NB:  digits = 0 has been valid in    options(digits = 0)  etc,
    >> "forever" I think, possibly inherited from S,  but I don't
    >> really know and I wonder if we should not  make it invalid eventually
    >> requiring at least 1.
    >> So we could make it raise a *warning* (and set it to '1') for  now.
    >> What do others think? 
    >> 
    >> Anyone with S(-PLUS) or Terr or .. who can report if  digits=0
    >> is allowed there and what it does in a simple situation like
    >> 
    >>> format(as.integer(2^30), digits=0) # digits not used at all
    >> [1] "1073741824"
    >>> format(2^30, digits=0)
    >> [1] "%#4.0-1e"
    >>> 
    >> 
    >> 
    >> Last but not least:  If you really want to use exponential
    >> format, you should typically use  sprintf() or formatC()  where
    >> you can tweak to get what you want.
    >> 
    >> ______________________________________________
    >> R-devel at r-project.org mailing list
    >> https://stat.ethz.ch/mailman/listinfo/r-devel

    > -- 
    > Peter Dalgaard, Professor,
    > Center for Statistics, Copenhagen Business School
    > Solbjerg Plads 3, 2000 Frederiksberg, Denmark
    > Phone: (+45)38153501
    > Office: A 4.23
    > Email: pd.mes at cbs.dk  Priv: PDalgd at gmail.com



[Rd] prettyNum digits=0 not compatible with scientific notation
Martin Maechler