检查数字是否为整数

我惊讶地发现,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)
}

我的方法在哪里会失败? 如果你处在我的假设的位置,你的工作是什么?

160106 次浏览

读取 R 语言档案编制时,as.integer与数字的存储方式的关系要大于它实际上是否等价于一个整数的关系。is.integer测试数字是否声明为整数。可以通过在整数后面加上 L来声明整数。

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

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

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

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

我不知道你想达到什么目的,但我有一些想法:
1. 转换为整数:
Num = as.int (123.2342)
2. 检查变量是否为整数:
整数(num)
Typeof (num) = = “ int”

另一种方法是检查小数部分:

x%%1==0

或者,如果你想在一定的容差范围内检查:

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

似乎您没有看到需要合并一些容错性。如果所有的整数都是以整数的形式输入的,那么就不需要这样做了,但是有时候它们是算术运算的结果,会导致一定的精度下降。例如:

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

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

这里有一个显然可靠的方法:

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

来自 Hmisc::spss.get:

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

更安全的选择,恕我直言,因为它“绕过”机器的精度问题。如果你尝试 is.integer(floor(1)),你会得到 FALSE。顺便说一句,如果你的整数大于 .Machine$integer.max值,它将不会被保存为整数,默认值是2147483647,所以要么改变 integer.max值,要么做替代检查..。

这里有一个解决方案,使用更简单的函数,不需要修改:

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

你可以使用简单的 if 条件,比如:

if(round(var) != var)­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­

在 R 中,数字是数字还是整数可以通过类函数来确定。一般来说,所有的数字都是以数字的形式存储的,要将数字显式定义为整数,我们需要在数字后面指定“ L”。

例如:

X <-1

类别(x)

[1]“数字”

X <-1L

类别(x)

[1]“整数”

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

如果您不喜欢编写自己的函数,请尝试 check.integer从软件包 安装。目前 它使用维托什卡的答案。

还可以从包 Varhandle中尝试 check.numeric(v, only.integer=TRUE),它具有向量化的好处。

[ UPDATE ] = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

关于下面这个[旧]答案,我发现它有效,因为我把所有的数字放在一个单一的原子向量中; 其中一个是字符,所以每个都成为字符。

如果我们使用一个列表(因此,强制不会发生) ,所有的测试都会正确通过,除了一个: 1/(1 - 0.98),它仍然是一个 numeric。这是因为 tol参数在默认情况下是 100 * .Machine$double.eps,而且这个数字远远低于 50的两倍。所以,基本上,对于这种数字,我们 来决定我们的容忍度!

所以如果你想所有的测试成为 TRUE,你可以 assertive::is_whole_number(x, tol = 200 * .Machine$double.eps)

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

下面是这个[更新]的 reprex。

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 软件包于2019-07-23年度创作(0.3.0版)

[ 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 软件包于2019-07-23年度创作(0.3.0版)

一次也可以使用 dplyr::near:

library(dplyr)


near(a, as.integer(a))

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

对于向量 mm[round(m) != m]将返回向量中非整数值的索引。