如何返回R中的小数位数

时间:2011-03-02 21:25:57

标签: r

我在R.工作。我有十进制度的一系列坐标,我想按这些数字的小数位数排序这些坐标(即我想丢弃小数位数太少的坐标) 。
R中是否有一个函数可以返回一个数字所具有的小数位数,我可以将其合并到函数编写中?
输入示例:

AniSom4     -17.23300000        -65.81700

AniSom5     -18.15000000        -63.86700

AniSom6       1.42444444        -75.86972

AniSom7       2.41700000        -76.81700

AniLac9       8.6000000        -71.15000

AniLac5      -0.4000000        -78.00000

理想情况下,我会编写一个会丢弃AniLac9和AniLac 5的脚本,因为这些坐标没有以足够的精度记录。我想丢弃经度和纬度都小于3的非零小数值的坐标。

12 个答案:

答案 0 :(得分:24)

您可以轻松地为任务编写一个小函数,例如:

decimalplaces <- function(x) {
    if ((x %% 1) != 0) {
        nchar(strsplit(sub('0+$', '', as.character(x)), ".", fixed=TRUE)[[1]][[2]])
    } else {
        return(0)
    }
}

并运行:

> decimalplaces(23.43234525)
[1] 8
> decimalplaces(334.3410000000000000)
[1] 3
> decimalplaces(2.000)
[1] 0

更新(2018年4月3日),以解决由于舍入双精度浮点数而导致错误的@ owen88报告 - 替换x %% 1检查:

decimalplaces <- function(x) {
    if (abs(x - round(x)) > .Machine$double.eps^0.5) {
        nchar(strsplit(sub('0+$', '', as.character(x)), ".", fixed = TRUE)[[1]][[2]])
    } else {
        return(0)
    }
}

答案 1 :(得分:9)

这是一种方法。它会检查小数点后的前20个位置,但如果您有其他想法,可以调整数字20。

x <- pi
match(TRUE, round(x, 1:20) == x)

这是另一种方式。

nchar(strsplit(as.character(x), "\\.")[[1]][2])

答案 2 :(得分:9)

罗马的建议:

num.decimals <- function(x) {
    stopifnot(class(x)=="numeric")
    x <- sub("0+$","",x)
    x <- sub("^.+[.]","",x)
    nchar(x)
}
x <- "5.2300000"
num.decimals(x)

如果您的数据不能保证格式正确,您应该进行更多检查以确保其他角色不会偷偷摸摸。

答案 3 :(得分:2)

我已经测试了一些解决方案,我发现该解决方案对其他报告的错误很健壮。

countDecimalPlaces <- function(x) {
  if ((x %% 1) != 0) {
    strs <- strsplit(as.character(format(x, scientific = F)), "\\.")
    n <- nchar(strs[[1]][2])
  } else {
    n <- 0
  }
  return(n) 
}

# example to prove the function with some values
xs <- c(1000.0, 100.0, 10.0, 1.0, 0, 0.1, 0.01, 0.001, 0.0001)
sapply(xs, FUN = countDecimalPlaces)

答案 4 :(得分:1)

在[R]中,2.30000和2.3之间没有区别,两者都被舍入到2.3,因此如果你想要检查,那么一个并不比另一个更精确。另一方面,如果这不是你的意思:如果你真的想这样做,你可以使用1)乘以10,2)使用floor()函数3)除以10 4)检查与原始的相等。 (但请注意,将浮点数比较为平等是不好的做法,请确保这确实是您想要的)

答案 5 :(得分:1)

对于常见的应用程序,这里修改daroczig的代码来处理向量:

decimalplaces <- function(x) {
    y = x[!is.na(x)]
    if (length(y) == 0) {
      return(0)
    }
    if (any((y %% 1) != 0)) {
      info = strsplit(sub('0+$', '', as.character(y)), ".", fixed=TRUE)
      info = info[sapply(info, FUN=length) == 2]
      dec = nchar(unlist(info))[seq(2, length(info), 2)]
      return(max(dec, na.rm=T))
    } else {
      return(0)
    }
}

通常,浮点数如何存储为二进制可能存在问题。试试这个:

> sprintf("%1.128f", 0.00000000001)
[1] "0.00000000000999999999999999939458150688409432405023835599422454833984375000000000000000000000000000000000000000000000000000000000"

我们现在有多少小数?

答案 6 :(得分:1)

不要劫持线程,只是将其发布在此处,因为它可能有助于某人处理我尝试使用建议的代码完成的任务。

不幸的是,即使the updated @ daroczig的解决方案也无法检查数字是否少于8位小数。

@ daroczig的代码:

decimalplaces <- function(x) {
    if (abs(x - round(x)) > .Machine$double.eps^0.5) {
        nchar(strsplit(sub('0+$', '', as.character(x)), ".", fixed = TRUE)[[1]][[2]])
    } else {
        return(0)
    }
}

在我的案例中产生了以下结果

NUMBER / NUMBER OF DECIMAL DIGITS AS PRODUCED BY THE CODE ABOVE
[1] "0.0000437 7"
[1] "0.000195 6"
[1] "0.00025 20"
[1] "0.000193 6"
[1] "0.000115 6"
[1] "0.00012501 8"
[1] "0.00012701 20"

到目前为止,能够使用以下笨拙的代码完成所需的测试:

if (abs(x*10^8 - floor(as.numeric(as.character(x*10^8)))) > .Machine$double.eps*10^8) 
   {
   print("The number has more than 8 decimal digits")
   }
PS:我可能会遗漏一些与.Machine$double.eps没有关系的内容,所以请小心

答案 7 :(得分:1)

另一个贡献,完全保留为数字表示形式,而无需转换为字符:

countdecimals <- function(x) 
{
  n <- 0
  while (!isTRUE(all.equal(floor(x),x)) & n <= 1e6) { x <- x*10; n <- n+1 }
  return (n)
}

答案 8 :(得分:1)

如果此处有人需要上述GergelyDaróczi提供的功能的矢量化版本:

Mon Nov 11 2019 00:00:00 GMT+0400 (Armenia Standard Time)

答案 9 :(得分:0)

有趣的问题。以下是对上述受访者的另一个调整。工作,矢量化和扩展以处理小数点左侧的数字。针对负数进行测试,这会导致先前strsplit()方法的结果不正确。

如果只想计算右边的那些,trailingonly参数可以设置为TRUE

nd1 <- function(xx,places=15,trailingonly=F) {
  xx<-abs(xx); 
  if(length(xx)>1) {
    fn<-sys.function();
    return(sapply(xx,fn,places=places,trailingonly=trailingonly))};
  if(xx %in% 0:9) return(!trailingonly+0); 
  mtch0<-round(xx,nds <- 0:places); 
  out <- nds[match(TRUE,mtch0==xx)]; 
  if(trailingonly) return(out); 
  mtch1 <- floor(xx*10^-nds); 
  out + nds[match(TRUE,mtch1==0)]
}

以下是strsplit()版本。

nd2 <- function(xx,trailingonly=F,...) if(length(xx)>1) {
  fn<-sys.function();
  return(sapply(xx,fn,trailingonly=trailingonly))
  } else {
    sum(c(nchar(strsplit(as.character(abs(xx)),'\\.')[[1]][ifelse(trailingonly, 2, T)]),0),na.rm=T);
  }

字符串版本以15位数字切断(实际上,不确定为什么另一个地方的论点被一个人关闭......它超越的原因是它计算了两个方向的数字如果数量足够大,它可以达到两倍大小)。 as.character()可能有一些格式化选项可以nd2()places nd1() nd1(c(1.1,-8.5,-5,145,5,10.15,pi,44532456.345243627,0)); # 2 2 1 3 1 4 16 17 1 nd2(c(1.1,-8.5,-5,145,5,10.15,pi,44532456.345243627,0)); # 2 2 1 3 1 4 15 15 1 参数提供等效选项。

nd1()

rowSums(replicate(10,system.time(replicate(100,nd1(c(1.1,-8.5,-5,145,5,10.15,pi,44532456.345243627,0)))))); rowSums(replicate(10,system.time(replicate(100,nd2(c(1.1,-8.5,-5,145,5,10.15,pi,44532456.345243627,0)))))); 更快。

 #Ingredients per 48 cookies
    sugar = 1.5
    butter = 1
    flour = 2.75

    #what percent of 48 are the ingredients
    sugar1 = (1.5/48)

    butter1 = (1/48)

    flour1 = (2.75/48)

    #ask for amount of cookies from user
    cookies = int (input('How many cookies would you like to bake? '))


    #calculate ingredient amounts
    sugar2 = (sugar1 * cookies)
    format(sugar2, '.2f')

    butter2 = (butter1 * cookies)
    format(butter2, '.2f')

    flour2 = (flour1 * cookies)
    format(flour2, '.2f')

    print ('To make', cookies, ' you need', sugar2, 'cups of sugar,',
           butter2, 'cups of butter, and', flour2, ' cups of flour.')

答案 10 :(得分:0)

基于daroczig函数的矢量解决方案(还可以处理包含字符串和数字的脏列):

chains =1

答案 11 :(得分:0)

不确定上面为什么不使用这种简单方法(从 tidyverse / magrittr 加载管道)。

count_decimals = function(x) {
  x_nchr = x %>% abs() %>% as.character() %>% nchar() %>% as.numeric()
  x_int = floor(x) %>% abs() %>% nchar()
  x_nchr = x_nchr - 1 - x_int
  x_nchr[x_nchr < 0] = 0

  x_nchr
}
> #test
> c(1, 1.1, 1.12, 1.123, 1.1234, 1.1, 1.10, 1.100, 1.1000) %>% count_decimals()
[1] 0 1 2 3 4 1 1 1 1
> c(1.1, 12.1, 123.1, 1234.1, 1234.12, 1234.123, 1234.1234) %>% count_decimals()
[1] 1 1 1 1 2 3 4
> seq(0, 1000, by = 100) %>% count_decimals()
 [1] 0 0 0 0 0 0 0 0 0 0 0
> c(100.1234, -100.1234) %>% count_decimals()
[1] 4 4

因此,R似乎没有内部区分最初获得1.0001的区别。因此,如果一个人的矢量输入包含各种十进制数字,则可以通过取小数位数的最大值来查看(至少)最初具有多少个数字。

编辑:已修复的错误