[Rd] significant digits (PR#9682)

pmc1 at cornell.edu pmc1 at cornell.edu
Tue Jun 3 01:40:17 CEST 2008


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:

    > 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.

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.

Pat Carr

version.string R version 2.7.0 (2008-04-22)



More information about the R-devel mailing list