检查数字是否为整数


104

我很惊讶地得知R没有附带方便的功能来检查数字是否为整数。

is.integer(66) # FALSE

帮助文件警告

is.integer(x)不测试是否x 包含整数!为此,请使用round,如is.wholenumber(x)示例中的函数 中所示。

该示例将此自定义功能作为“解决方法”

is.wholenumber <- function(x, tol = .Machine$double.eps^0.5)  abs(x - round(x)) < tol
is.wholenumber(1) # is TRUE

如果我不得不编写一个函数来检查整数,并假设我没有阅读上面的注释,那么我写的函数将遵循

check.integer <- function(x) {
    x == round(x)
}

我的方法在哪里失败?如果您穿着我的假想鞋,您将如何处理?


我希望,如果round(x)实施得当,将其应用于整数的结果将始终是该整数……
斯蒂芬,


5
> check.integer(9.0)[1]是,不是。
彭彭

@ PengPeng,VitoshKa在已接受的答案中解决了此问题。
RomanLuštrik'12

4
我认为整数的数学和计算概念令人困惑。函数is.integer检查计算概念,check.integer用户函数检查数学观点。
若奥·丹尼尔·

Answers:


126

另一种选择是检查小数部分:

x%%1==0

或者,如果您想在一定的公差范围内进行检查:

min(abs(c(x%%1, x%%1-1))) < tol

1
公差检查建议真的有效吗? x <- 5-1e-8; x%%1给出0.9999999(这将意味着如果tol==1e-5例如),其x为整数。
Ben Bolker 2014年

@BenBolker不错,我认为它可以带来积极的摄动。我将其更改为应该可以使用的替代解决方案。
詹姆斯

2
@James,我认为应该以其他方式min(abs(c(x%%1, x%%1-1))) < tol代替abs(min(x%%1, x%%1-1)) < tol,您可以FALSE获取任何整数...
Cath 2015年

3
这有什么错as.integer(x) == x?它不会像以前那样拒绝3或3.0 is.integer(x),它将捕获3.1。
加比2015年

34

这是使用更简单的功能且没有任何技巧的解决方案:

all.equal(a, as.integer(a))

此外,如果愿意,您可以一次测试整个向量。这是一个函数:

testInteger <- function(x){
  test <- all.equal(x, as.integer(x), check.attributes = FALSE)
  if(test == TRUE){ return(TRUE) }
  else { return(FALSE) }
}

您可以更改它以用于*apply向量,矩阵等。


11
最后一个if else可以简单地完成isTRUE(test)。实际上,您只需要替换if else子句和return语句即可,因为R自动返回上一次求值的结果。
加文·辛普森

7
testInteger(1.0000001)[1]假 testInteger(1.00000001)[1]是
PatrickT 2015年

3
all(a == as.integer(a))解决这个问题!
亚历克斯(Alex)

这不能正常工作!看看下面的反例:frac_test < - 1 /(1-0.98),all.equal(frac_test,as.integer(frac_test)),IsTrue运算(all.equal(frac_test,as.integer(frac_test)))
tstudio

11

阅读R语言文档as.integer与数字的存储方式相比,实际上与一个整数等效,更多的是与数字的存储方式有关。is.integer测试数字是否声明为整数。您可以通过在L其后放置一个整数来声明一个整数。

> is.integer(66L)
[1] TRUE
> is.integer(66)
[1] FALSE

同样的函数,例如roundwill将返回一个声明的整数,这就是您正在使用的x==round(x)。这种方法的问题是您认为实际上是整数。该示例使用较低的精度测试等效性。

> is.wholenumber(1+2^-50)
[1] TRUE
> check.integer(1+2^-50)
[1] FALSE

因此,根据您的应用程序,您可能会遇到这种麻烦。


1
第二行说“ as.integer测试数字是否声明为整数”。但我很确定您的意思是“ is.integer”。这只是一个字符的编辑,所以我很难更改它。
PeterVermont

10

这是一种看似可靠的方法:

check.integer <- function(N){
    !grepl("[^[:digit:]]", format(N,  digits = 20, scientific = FALSE))
}

check.integer(3243)
#TRUE
check.integer(3243.34)
#FALSE
check.integer("sdfds")
#FALSE

此解决方案还允许使用科学计数形式的整数:

> check.integer(222e3)
[1] TRUE

1
这对我来说似乎不是很可靠:check.integer(1e4)是TRUE,check.integer(1e5)而是FALSE。
wch 2012年

5
-1这比is.wholenumber或其他答案中提供的任何其他解决方案还差。这些应该没有什么不同:check.integer(1e22); check.integer(1e23)。您显然可以更改正则表达式来解决此问题,但是这种方法令人恐惧。(评论来自安装程序包中的署名。)
Joshua Ulrich

1
@PatrickT,我知道了。这是默认数字的参数。使用format(40, scientific = FALSE, digits = 20)代替。我已经更新了答案。感谢您发现它。
VitoshKa

1
@PatrickT您处于依赖于机器的舍入错误的领域。在这方面,我的解决方案与公认的解决方案相同1.0000000000000001 == 1L [1] TRUE。但是,如果您已经获得字符串形式的数字,我的解决方案会更好check.integer("1000000000000000000000000000000000001") [1] TRUE
VitoshKa 2015年

4
@VitoshKa喜欢您的回答!尽管您遗漏了一点,但没有小数点的负数也是整数;)我相应地修改了代码。
Mehrad Mahmoudian 2015年

8

看来您看不到需要合并一些容错功能。如果所有整数都作为整数输入,则不需要,但是有时它们是由于算术运算而失去一定精度的结果。例如:

> 2/49*49
[1] 2
> check.integer(2/49*49)
[1] FALSE 
> is.wholenumber(2/49*49)
[1] TRUE

请注意,这不是R的弱点,所有计算机软件都有一定的精度限制。


3
万一有些人不太了解这里发生的事情...如果输入as.integer(2/49 * 49),您将得到1![顺便说一句,它是有史以来如此令人沮丧的是,R不为2.0呈现初始计算的结果来表示的值有一定的小数成分)看到... stackoverflow.com/questions/1535021/...
约翰

6

来自Hmisc::spss.get

all(floor(x) == x, na.rm = TRUE)

恕我直言,这是更安全的选择,因为它“绕过”了机器精度问题。如果你尝试的话is.integer(floor(1)),你会得到的FALSE。顺便说一句,如果您的整数大于.Machine$integer.max值,则该整数将不另存为整数,默认情况下为2147483647,因此请更改该integer.max值或进行替代检查...


1
如果x <- sqrt(2)^2,则all(floor(x) == x, na.rm = TRUE)返回FALSE
Corrado


1

在R中,数字是数字还是整数可以由类函数确定。通常所有数字都存储为数字,并且要将数字显式定义为整数,我们需要在数字后指定“ L”。

例:

x <-1

类(x)

[1]“数字”

x <-1公升

类(x)

[1]“整数”

我希望这是需要的。谢谢 :)


0

[更新] =============================================== ===============

关于下面的[OLD]答案,我发现它起作用是因为我将所有数字都放在一个原子向量中。其中一个是角色,所以每个人都成为角色。

如果我们使用列表(因此,不会发生强制转换),则所有测试均正确通过,但one:1/(1 - 0.98)仍然通过numeric。这是因为tol默认情况下该参数是该参数,100 * .Machine$double.eps并且该数字远50小于该参数的两倍。因此,基本上,对于这种数字,我们必须确定我们的容忍度!

因此,如果您希望所有测试都变成了TRUE,您可以assertive::is_whole_number(x, tol = 200 * .Machine$double.eps)

无论如何,我确认IMO自信仍然是最好的解决方案。

下面是此[UPDATE]的代表。

expect_trues_c <- c(
  cl = sqrt(2)^2,
  pp = 9.0,
  t = 1 / (1 - 0.98),
  ar0 = 66L,
  ar1 = 66,
  ar2 = 1 + 2^-50,
  v = 222e3,
  w1 = 1e4,
  w2 = 1e5,
  v2 = "1000000000000000000000000000000000001",
  an = 2 / 49 * 49,
  ju1 = 1e22,
  ju2 = 1e24,
  al = floor(1),
  v5 = 1.0000000000000001 # this is under machine precision!
)

str(expect_trues_c)
#>  Named chr [1:15] "2" "9" "50" "66" "66" "1" "222000" "10000" "1e+05" ...
#>  - attr(*, "names")= chr [1:15] "cl" "pp" "t" "ar0" ...
assertive::is_whole_number(expect_trues_c)
#> Warning: Coercing expect_trues_c to class 'numeric'.
#>                      2                      9                     50 
#>                   TRUE                   TRUE                   TRUE 
#>                     66                     66                      1 
#>                   TRUE                   TRUE                   TRUE 
#>                 222000                  10000                 100000 
#>                   TRUE                   TRUE                   TRUE 
#>                  1e+36                      2                  1e+22 
#>                   TRUE                   TRUE                   TRUE 
#> 9.9999999999999998e+23                      1                      1 
#>                   TRUE                   TRUE                   TRUE



expect_trues_l <- list(
  cl = sqrt(2)^2,
  pp = 9.0,
  t = 1 / (1 - 0.98),
  ar0 = 66L,
  ar1 = 66,
  ar2 = 1 + 2^-50,
  v = 222e3,
  w1 = 1e4,
  w2 = 1e5,
  v2 = "1000000000000000000000000000000000001",
  an = 2 / 49 * 49,
  ju1 = 1e22,
  ju2 = 1e24,
  al = floor(1),
  v5 = 1.0000000000000001 # this is under machine precision!
)

str(expect_trues_l)
#> List of 15
#>  $ cl : num 2
#>  $ pp : num 9
#>  $ t  : num 50
#>  $ ar0: int 66
#>  $ ar1: num 66
#>  $ ar2: num 1
#>  $ v  : num 222000
#>  $ w1 : num 10000
#>  $ w2 : num 1e+05
#>  $ v2 : chr "1000000000000000000000000000000000001"
#>  $ an : num 2
#>  $ ju1: num 1e+22
#>  $ ju2: num 1e+24
#>  $ al : num 1
#>  $ v5 : num 1
assertive::is_whole_number(expect_trues_l)
#> Warning: Coercing expect_trues_l to class 'numeric'.
#> There was 1 failure:
#>   Position              Value      Cause
#> 1        3 49.999999999999957 fractional
assertive::is_whole_number(expect_trues_l, tol = 200 * .Machine$double.eps)
#> Warning: Coercing expect_trues_l to class 'numeric'.
#>     2.0000000000000004                      9     49.999999999999957 
#>                   TRUE                   TRUE                   TRUE 
#>                     66                     66     1.0000000000000009 
#>                   TRUE                   TRUE                   TRUE 
#>                 222000                  10000                 100000 
#>                   TRUE                   TRUE                   TRUE 
#>                  1e+36     1.9999999999999998                  1e+22 
#>                   TRUE                   TRUE                   TRUE 
#> 9.9999999999999998e+23                      1                      1 
#>                   TRUE                   TRUE                   TRUE



expect_falses <- list(
  bb = 5 - 1e-8,
  pt1 = 1.0000001,
  pt2 = 1.00000001,
  v3 = 3243.34,
  v4 = "sdfds"
)

str(expect_falses)
#> List of 5
#>  $ bb : num 5
#>  $ pt1: num 1
#>  $ pt2: num 1
#>  $ v3 : num 3243
#>  $ v4 : chr "sdfds"
assertive::is_whole_number(expect_falses)
#> Warning: Coercing expect_falses to class 'numeric'.
#> Warning in as.this_class(x): NAs introduced by coercion
#> There were 5 failures:
#>   Position              Value      Cause
#> 1        1 4.9999999900000001 fractional
#> 2        2 1.0000001000000001 fractional
#> 3        3 1.0000000099999999 fractional
#> 4        4 3243.3400000000001 fractional
#> 5        5               <NA>    missing
assertive::is_whole_number(expect_falses, tol = 200 * .Machine$double.eps)
#> Warning: Coercing expect_falses to class 'numeric'.

#> Warning: NAs introduced by coercion
#> There were 5 failures:
#>   Position              Value      Cause
#> 1        1 4.9999999900000001 fractional
#> 2        2 1.0000001000000001 fractional
#> 3        3 1.0000000099999999 fractional
#> 4        4 3243.3400000000001 fractional
#> 5        5               <NA>    missing

reprex软件包(v0.3.0)创建于2019-07-23

[OLD] ================================================ ==================

IMO最好的解决方案来自assertive程序包(目前,该程序包解决了该线程中的所有正面和负面示例):

are_all_whole_numbers <- function(x) {
  all(assertive::is_whole_number(x), na.rm = TRUE)
}

are_all_whole_numbers(c(
  cl = sqrt(2)^2,
  pp = 9.0,
  t = 1 / (1 - 0.98),
  ar0 = 66L,
  ar1 = 66,
  ar2 = 1 + 2^-50,
  v = 222e3,
  w1 = 1e4,
  w2 = 1e5,
  v2 = "1000000000000000000000000000000000001",
  an = 2 / 49 * 49,
  ju1 = 1e22,
  ju2 = 1e24,
  al = floor(1),
  v5 = 1.0000000000000001 # difference is under machine precision!
))
#> Warning: Coercing x to class 'numeric'.
#> [1] TRUE

are_all_not_whole_numbers <- function(x) {
  all(!assertive::is_whole_number(x), na.rm = TRUE)
}

are_all_not_whole_numbers(c(
  bb = 5 - 1e-8,
  pt1 = 1.0000001,
  pt2 = 1.00000001,
  v3 = 3243.34,
  v4 = "sdfds"
))
#> Warning: Coercing x to class 'numeric'.
#> Warning in as.this_class(x): NAs introduced by coercion
#> [1] TRUE

reprex软件包(v0.3.0)创建于2019-07-23



0

一次也可以使用dplyr::near

library(dplyr)

near(a, as.integer(a))

它适用于任何矢量a,并具有可选的公差参数。


-3

我不确定您要完成什么。但是这里有一些想法:
1.转换为整数:
num = as.integer(123.2342)
2.检查变量是否为整数:
is.integer(num)
typeof(num)=="integer"


我只是确保用户输入一个适当的数字-我们所谈论的是“主题”的数量,它只能是整数。
RomanLuštrik2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.