【问题标题】:Fixed and decimal places of a positive number正数的固定位和小数位
【发布时间】:2020-06-08 21:29:33
【问题描述】:

我想写一个函数来计算每个正数的固定位数和小数位数。对于整数:例如,对于数字 459,我想查看

fixed=3 and decimal=0

作为函数的输出。 对于十进制数:例如,对于数字 12.657,我想查看

fixed=2 and decimal=3

(因为 12 有两位数,而 657 有三位)。对于小于 1 的数字,我希望看到

0 

作为固定值,例如数字 0.4056 我想看看

fixed=0 and decimal=4 

或者对于数字 0.13 我想看看

fixed=0 and decimal=2

我的大致思路如下:

digits<-function(x){
  length(strsplit(as.character(x),split="")[[1]])
}

我想将我的代码扩展为一个新代码,以便按照我上面的解释工作。

【问题讨论】:

  • 假设你有一个向量v1 &lt;- c(12, 12.657, 12.1) 输出是什么,即打印值为v1# [1] 12.000 12.657 12.100
  • 我的输入不是向量。我有一个数字作为输入。例如:对于 12,我希望看到 fixed=2 和 dcimal=0,对于 12.657,我希望看到 fixed=2 和 decimal=3,最后对于 12.1 作为输入,我希望看到 fixed=2 和小数=1 在输出中。
  • 是数字格式还是字符串
  • 使用 as.character 函数,我们可以将数字转换为字符串,然后使用该字符串。
  • 这是次要的,但 "my input is not a vector" 可能是短视的:让你的函数处理单个值和任意长度的向量 up-前端,这个函数的性能会明显更好,适应更多的情况。 (当它应该预先矢量化时,一直使用sapply 会让人厌烦。)

标签: r decimal fixed digits


【解决方案1】:

您似乎有点希望可以做到这一点。好吧,这是一个粗略的方法:

fun <- function(x){
  stopifnot(is.numeric(as.numeric(x)))
  s = nchar(unlist(strsplit(as.character(x),".",fixed = TRUE)))
  if(as.numeric(x) < 1) s[1] <- s[1]-1
  setNames(as.list(s),c("fixed","decimal"))
}

CORRECT:

fun(10.234)
$fixed
[1] 2

$decimal
[1] 3

fun(-10.234)
$fixed
[1] 2

$decimal
[1] 3

fun(0.2346)
$fixed
[1] 0

$decimal
[1] 4

> fun(-0.2346)
$fixed
[1] 0

$decimal
[1] 4

INCORRECT: Note that fixed + decimal <=15!!!

fun(-10000567.2346678901876)
$fixed
[1] 8

$decimal
[1] 7 ## This is incorrect

正确的值为:

fun("-10000567.2346678901876") # Note that the input x is a string
$fixed
[1] 8

$decimal
[1] 13

【讨论】:

  • 感谢您对我们说的代码和重要大小写固定+十进制
  • 我们如何修复您的代码,使其在数字输入(如 10000567.2346678901876)时正常工作? @Onyambu
  • 您的代码不适用于 -1
【解决方案2】:

我不认为这是可以做到的。我们不能假设一个简单的数值可以在计算机中准确表示。大多数浮点值当然不能。

在 R 控制台输入 0.3:

> 0.3
[1] 0.3

看起来不错,不是吗?但是现在,让我们这样做:

> print(0.3, digits=22)
[1] 0.29999999999999999

本质上,如果您将浮点数转换为字符串定义您想要的精确度。计算机无法为您提供该精度,因为它以位存储所有数字,因此永远不会为您提供绝对精度。即使您看到数字为 0.3 并且因此认为它有 0 个固定数字和 1 个小数,这是因为 R 选择了以这种方式打印它,而不是因为这是计算机内存中表示的数字。

其他答案证明一个函数可以处理简单的情况。我必须承认,我了解到 R 在解释数字方面做得非常出色。但我们必须谨慎使用! 一旦我们开始转换数字,这样的功能就不能保证有意义的结果

【讨论】:

  • 我明白你的解释。但是对于您的示例,即 0.3,我希望看到 fixed=0 和 decimal=1 作为输出。
  • 此代码:digits
  • 不同之处在于整数(即整数)数字可以“按原样”在计算机中表示。小数不能。
  • 我认为例如对于数字 12.456,我们可以使用 as.character() 函数将其转换为字符串。它将是“12.456”。然后我们可以考虑点(.)将字符串分成两部分,我的意思是“12”和“456”然后找到每个部分的数字(长度)。
  • @vahid 您应该知道的是,您不能将小数完全存储在计算机中。这只是一个近似值。因此,有时您会得到不正确的结果
【解决方案3】:

已编辑(基于 cmets):

以下函数适用于有效数字为 15 或更少的数字:

digits<-function(x){
  ## make sure x is a number, if not stop 
  tryCatch(
    {
      x/1
    },
    error=function(cond) {
      stop('x must be a number')
    }
  )
  ## use nchar() and strsplit() to determine number of digits before decimal point
  fixed<-nchar(strsplit(as.character(x),"\\.")[[1]][1])
  ## check if negative
  if(substr(strsplit(as.character(x),"\\.")[[1]][1],1,1)=="-"){fixed<-fixed-1}
  ## check if -1<x<1
  if(as.numeric(strsplit(as.character(x),"\\.")[[1]][1])==0){fixed<-fixed-1}
  ## use nchar() and strsplit() to determine number of digits after decimal point
  decimal<-nchar(strsplit(as.character(x),"\\.")[[1]][2])
  ## for integers, replace NA decimal result with 0
  if(is.na(nchar(strsplit(as.character(x),"\\.")[[1]][2]))){decimal<-0}
  ## return results
  print(paste0("fixed: ",fixed," and decimal: ", decimal))
}

如果您想将负号 (-) 计为数字,则需要删除:

## check if negative
if(substr(strsplit(as.character(x),"\\.")[[1]][1],1,1)=="-"){fixed<-fixed-1}

注意:15 位或更少有效数字的限制基于 8 字节浮点表示。

我能够克服这个问题的唯一方法是使用下面的代码。

digits<-function(x){
  tryCatch(
    {
      as.numeric(x)/1
    },
    error=function(cond) {
      stop('x must be a number')
    }
  )
  j <- 0
  num <- x
  fixed <- 0
  decimal <- 0
  for(i in 1:nchar(x)){
    if(substr(num, i, i) == "."){
      j <- 1
    } else if(j==0){
      fixed <- fixed + 1
    } else{
      decimal <- decimal + 1
    }
  }
  if(substr(x,1,1)=="-" & substr(as.numeric(x),2,2)==0){
    fixed<-fixed-2
  }else if(substr(x,1,1)=="-"){
    fixed<-fixed-1
  }else if(substr(as.numeric(x),1,1)==0){
    fixed<-fixed-1
  }else{}
  print(paste0("fixed: ",fixed," and decimal: ", decimal))
}

但是,此代码需要将数字作为字符串传递给函数,以便计算传递的 15 位有效数字,如下所示:

x<-"111111111111111111111111111111111111.22222222222222222222222222222222222222222222222"
digits(x)

返回:

[1]“固定:36,十进制:47”

这会限制此函数的应用程序,因为它不能在dplyr 管道中使用,并且您将不会收到先前四舍五入的数字的准确结果。例如,使用与上面相同的数字,但将其存储为数字而不是字符串会产生以下结果:

x<-111111111111111111111111111111111111.22222222222222222222222222222222222222222222222
digits(x)

[1]“固定:1,十进制:18”

我希望这至少会有所帮助!

【讨论】:

  • 这个函数不能工作,因为它没有使用参数x
  • 当我将它与1/3 一起使用时,我得到fixed: 1 and decimal: 15。但是当我检查 print(1/3, digits=16) 并且 - 显然 - 我没有得到 0.3333333333333330 而是 0.3333333333333333 有 16 个 3s。 1/3 的真实结果是什么?
  • 我不想检查 1/3 或 1/7 等分数的函数。我需要浮点数的函数,如 1.323、0.3 或 12.34 我的意思是具有特定小数位数的数字。
  • @vahid 那么这应该适合你。最美好的祝愿!
  • @vahid 这是因为我使用了message() 函数。如果您需要将输出用作对象(或者如果您更喜欢黑色输出),可以将其更改为 print() 函数。我假设由于您正在寻找返回的短语而不是 vector/list/data.frame,因此您更喜欢 message() 函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多