From murdoch at stats.uwo.ca  Tue Jun  3 12:36:44 2008
From: murdoch at stats.uwo.ca (Duncan Murdoch)
Date: Tue, 03 Jun 2008 06:36:44 -0400
Subject: [Rd] significant digits (PR#9682)
In-Reply-To: <20080602234017.CB1FD282C786@mail.pubhealth.ku.dk>
References: <20080602234017.CB1FD282C786@mail.pubhealth.ku.dk>
Message-ID: <48451EBC.1000207@stats.uwo.ca>

pmc1 at cornell.edu wrote:
> I came to report this same bug and found it already in the trash, but
> I slightly disagree with that assessment. If it's not a bug, then
> perhaps it's a feature request. Comments at the end.
>
> On Mon, May 14, 2007, Duncan Murdoch wrote:
>   
>>> On 13/05/2007 8:46 PM, scott.wilkinson at csiro.au wrote:
>>>
>>> In the example below round() does not report to the specified number of
>>> digits when the last digit to be reported is zero: Compare behaviour for
>>> 0.897575 and 0.946251. Ditto for signif(). The number of sigfigs is
>>> ambiguous unless the reader knows this behaviour. Is this a bug or
>>> intended behaviour? Is there a work-around?
>>>       
>> It's not a bug.  It has nothing to do with round(), it is the way R
>> prints numbers by default.  If you ask to print 0.90, you'll get
>>
>> [1] 0.9
>>
>> because 0.9 and 0.90 are the same number.  If you want trailing zeros to
>> print, you need to specify a format to do that, e.g.
>>
>>     
>>> noquote(format(0.9, nsmall=2))
>>>       
>> [1] 0.90
>>
>> The noquote stops the "" from printing.  You could also use sprintf() or
>> formatC() for more C-like format specifications.
>>     
>
> All of those options require you to specify the number of digits after
> the decimal, don't they? Unless sprintf would default to the number of
> decimal places passed to it, but it doesn't:
>   

That specification doesn't make sense.  There is no "number of decimal 
places passed to it".  What sprintf() sees below is identical to what it 
would see if you called

sprintf("%f", 0.9)

because signif(0.90, digits=2) == 0.9.  Those two objects are identical.
>     > sprintf("%f",signif(0.90, digits=2))
>     [1] "0.900000";
>
> it defaults to 6. Although %g behaves differently,
>
>     > sprintf("%g",signif(0.90, digits=2))
>     [1] "0.9",
>
> this clearly still isn't the desired behavior.
>   

Maybe not what you desired, but certainly reasonable behaviour.  
> To continue that vein, the same issue with rounding versus printing
> occurs with vectors:
>
>       > sapply(c(1:6),function(a){signif(c(18.423,0.90),digits=a)})
>           [,1] [,2] [,3]  [,4]   [,5]   [,6]
>      [1,] 20.0 18.0 18.4 18.42 18.423 18.423
>      [2,]  0.9  0.9  0.9  0.90  0.900  0.900
>
> Trying to get that and more complicated tables to print the correct
> number of significant digits gets pretty hairy with sprintf(). I could
> be wrong, but I would view the primary purpose of rounding to
> significant digits the printed output of the number. That there
> doesn't seem to be a way to do this without later having to specify
> the number of decimal places would seem to render signif() as it's
> written not particularly useful.
>
> There are two solutions I can think of off the top of my head. The
> first is to create a new data type of a fixed length real number but
> the easier way would be to have a function that returns a string
> something like this:
>
> signif.string <- function(signum,sigdigs){
>   left <- nchar(trunc(signum))
>   right <- nchar(signum-trunc(signum))-2
>   if (abs(signum)<1 | signum<0) {left<-left-1}
>   if (right<0) {right<-0}
>   if (sigdigs<left) {return(as.character(signif(signum,digits=sigdigs)))}
>   else if (sigdigs==left) {return(paste(round(signum),".",sep=""))}
>   else if (sigdigs<=left+right) {return(format(signum,digits=sigdigs))}
>   else {return(sprintf(paste("%.",sigdigs-left,"f",sep=""),signum))}
> }
>
>   
> This is just a skeleton that I think suits my needs for the moment and
> might also cover the original poster's. One for production would need
> to handle scientific notation and would probably want to fix the 5
> round behavior on windows.
>   

As far as I know, rounding is fine in Windows:

 > round(1:10 + 0.5)
 [1]  2  2  4  4  6  6  8  8 10 10

looks okay to me.  If you want biased rounding instead (getting 2:11 as 
output), simply use trunc(x + 0.5) instead of round(x).

Duncan Murdoch
> Pat Carr
>
> version.string R version 2.7.0 (2008-04-22)
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>



[Rd] significant digits (PR#9682)
Duncan Murdoch