Kiểm tra xem số có phải là số nguyên không


104

Tôi rất ngạc nhiên khi biết rằng R không đi kèm với một chức năng tiện dụng để kiểm tra xem số có phải là số nguyên hay không.

is.integer(66) # FALSE

Các tệp trợ giúp cảnh báo :

is.integer(x)không kiểm tra nếu x chứa số nguyên! Đối với điều đó, hãy sử dụng round, như trong hàm is.wholenumber(x)trong các ví dụ.

Ví dụ có chức năng tùy chỉnh này như một "giải pháp thay thế"

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

Nếu tôi phải viết một hàm để kiểm tra các số nguyên, giả sử tôi chưa đọc các nhận xét ở trên, tôi sẽ viết một hàm sẽ đi theo dòng của

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

Cách tiếp cận của tôi sẽ thất bại ở đâu? Công việc của bạn sẽ thế nào nếu bạn ở trong đôi giày giả định của tôi?


Tôi hy vọng rằng nếu round(x)được triển khai đúng cách, kết quả của việc áp dụng nó cho một số nguyên sẽ luôn là số nguyên đó ...
Stephen

Hãy xem Câu hỏi thường gặp trên R cran.r-project.org/doc/FAQ/…
Richie Cotton

5
> check.integer (9.0) [1] ĐÚNG là không.
Peng Peng,

@PengPeng, VitoshKa đã sửa lỗi này trong câu trả lời được chấp nhận.
Roman Luštrik,

4
Tôi nghĩ rằng có một sự nhầm lẫn về các khái niệm toán học và tính toán của số nguyên. Hàm is.integerkiểm tra khái niệm tính toán, check.integerhàm người dùng kiểm tra quan điểm toán học.
João Daniel

Câu trả lời:


126

Một cách thay thế khác là kiểm tra phần phân số:

x%%1==0

hoặc, nếu bạn muốn kiểm tra trong một dung sai nhất định:

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

1
đề xuất kiểm tra dung sai có thực sự hoạt động không ?? x <- 5-1e-8; x%%1cho 0.9999999 (mà sẽ bao hàm nếu tol==1e-5ví dụ) mà xkhông một số nguyên.
Ben Bolker

@BenBolker Bắt tốt, tôi nghĩ nó hoạt động với những xáo trộn tích cực. Tôi đã thay đổi nó thành một giải pháp thay thế sẽ hoạt động.
James

2
@James, tôi nghĩ nó nên được min(abs(c(x%%1, x%%1-1))) < tolthay vì abs(min(x%%1, x%%1-1)) < tolbằng cách khác, bạn sẽ nhận được FALSEbất kỳ số nguyên nào ...
Cath

3
Có chuyện gì vậy as.integer(x) == x? Nó sẽ không từ chối 3 hoặc 3.0 như is.integer(x)muốn, và nó sẽ bắt 3.1.
Gabi

34

Đây là một giải pháp sử dụng các chức năng đơn giản hơn và không có hack:

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

Hơn nữa, bạn có thể kiểm tra toàn bộ vectơ cùng một lúc, nếu muốn. Đây là một chức năng:

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

Bạn có thể thay đổi nó để sử dụng *applytrong trường hợp vectơ, ma trận, v.v.


11
Cuối cùng if elsecó thể được thực hiện đơn giản isTRUE(test). Thật vậy, đó là tất cả những gì bạn cần để thay thế if elsemệnh đề và các returncâu lệnh vì R tự động trả về kết quả của lần đánh giá cuối cùng.
Gavin Simpson

7
testInteger(1.0000001)[1] FALSE testInteger(1.00000001)[1] TRUE
PatrickT

3
all(a == as.integer(a))giải quyết vấn đề này! '
Alex

Điều này không hoạt động bình thường! Kiểm tra ví dụ phản chứng sau: 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

Việc đọc tài liệu ngôn ngữ R as.integercó liên quan nhiều hơn đến cách số được lưu trữ hơn là nếu nó thực tế tương đương với một số nguyên. is.integerkiểm tra nếu số được khai báo là số nguyên. Bạn có thể khai báo một số nguyên bằng cách đặt Lsau nó.

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

Ngoài ra, các hàm như roundsẽ trả về một số nguyên đã khai báo, đó là những gì bạn đang làm với x==round(x). Vấn đề với cách tiếp cận này là những gì bạn cho là thực tế là một số nguyên. Ví dụ này sử dụng độ chính xác thấp hơn để kiểm tra tính tương đương.

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

Vì vậy, tùy thuộc vào ứng dụng của bạn, bạn có thể gặp rắc rối theo cách đó.


1
Dòng thứ hai cho biết "as.integer kiểm tra nếu số được khai báo là số nguyên". nhưng tôi khá chắc ý của bạn là "is.integer". Nó chỉ là một chỉnh sửa một nhân vật nên tôi không thể dễ dàng thay đổi nó.
PeterVermont

10

Đây là một cách, có vẻ đáng tin cậy:

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

Giải pháp này cũng cho phép các số nguyên trong ký hiệu khoa học:

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

1
Điều này có vẻ không đáng tin cậy đối với tôi: check.integer(1e4)là ĐÚNG, trong khi check.integer(1e5)là SAI.
wch 14/02/12

5
-1 Điều này tệ hơn is.wholenumber, hoặc bất kỳ giải pháp nào khác được cung cấp trong các câu trả lời khác. Những không nên khác nhau: check.integer(1e22); check.integer(1e23). Rõ ràng là bạn có thể thay đổi regex để sửa lỗi này, nhưng cách làm này rất tệ. (Nhận xét đến từ phân bổ trong gói trình cài đặt.)
Joshua Ulrich

1
@PatrickT, tôi hiểu rồi. Đó là đối số của chữ số mặc định. sử dụng format(40, scientific = FALSE, digits = 20)thay thế. Tôi đã cập nhật câu trả lời. Cảm ơn vì đã phát hiện ra nó.
VitoshKa

1
@PatrickT Bạn đang gặp lỗi làm tròn phụ thuộc vào máy. Về mặt đó, giải pháp của tôi giống với giải pháp được chấp nhận 1.0000000000000001 == 1L [1] TRUE. Nhưng giải pháp của tôi tốt hơn nếu bạn đã nhận được một số ở dạng chuỗicheck.integer("1000000000000000000000000000000000001") [1] TRUE
VitoshKa

4
@VitoshKa thích câu trả lời của bạn! Mặc dù có một điểm mà bạn đã bỏ qua, các số âm không có dấu thập phân cũng là số nguyên;) Tôi đã sửa đổi mã của bạn cho phù hợp.
Mehrad Mahmoudian

8

Có vẻ như bạn không thấy cần phải kết hợp một số khả năng chịu lỗi. Sẽ không cần thiết nếu tất cả các số nguyên được nhập dưới dạng số nguyên, tuy nhiên, đôi khi chúng đến là kết quả của các phép toán số học làm mất độ chính xác. Ví dụ:

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

Lưu ý rằng đây không phải là điểm yếu của R, tất cả các phần mềm máy tính đều có một số giới hạn về độ chính xác.


3
đề phòng một số người không hiểu những gì đã xảy ra ở đây ... nếu bạn nhập as.integer (2/49 * 49), bạn sẽ nhận được 1 !! [BTW, thật bực bội khi R không hiển thị kết quả của phép tính ban đầu là 2,0 để biểu thị rằng giá trị có một số thành phần thập phân) xem ... stackoverflow.com/questions/1535021/…
John

6

Từ Hmisc::spss.get:

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

tùy chọn an toàn hơn nhiều, IMHO, vì nó "bỏ qua" vấn đề về độ chính xác của máy. Nếu bạn cố gắng is.integer(floor(1)), bạn sẽ nhận được FALSE. BTW, số nguyên của bạn sẽ không được lưu dưới dạng số nguyên nếu nó lớn hơn .Machine$integer.maxgiá trị, theo mặc định là 2147483647, vì vậy hãy thay đổi integer.maxgiá trị hoặc thực hiện các kiểm tra thay thế ...


1
nếu x <- sqrt(2)^2, sau đó all(floor(x) == x, na.rm = TRUE)trở lạiFALSE
Corrado

3

bạn có thể sử dụng đơn giản nếu điều kiện như:

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

1

Trong R, một số là số hay số nguyên có thể được xác định bằng hàm lớp. Nói chung, tất cả các số được lưu trữ dưới dạng số và để xác định rõ ràng một số là số nguyên, chúng ta cần chỉ định 'L' sau số.

Thí dụ:

x <- 1

lớp (x)

[1] "số"

x <- 1L

lớp (x)

[1] "số nguyên"

Tôi hy vọng đây là những gì cần thiết. Cảm ơn :)


0

[CẬP NHẬT] ================================================= ===============

Tôn trọng câu trả lời [CŨ] ở đây dưới đây, tôi đã phát hiện ra rằng nó hoạt động vì tôi đã đặt tất cả các số trong một vectơ nguyên tử; một trong số họ là một nhân vật, vì vậy mọi người đều trở thành nhân vật.

Nếu chúng ta sử dụng một danh sách (do đó, sự ép buộc không xảy ra) thì tất cả các bài kiểm tra đều vượt qua chính xác ngoại trừ một 1/(1 - 0.98):, cái vẫn là a numeric. Điều này bởi vì toltham số là theo mặc định 100 * .Machine$double.epsvà con số đó 50không nhỏ hơn gấp đôi. Vì vậy, về cơ bản, đối với loại con số này, chúng ta phải quyết định khả năng chịu đựng của mình!

Vì vậy, nếu bạn muốn tất cả các thử nghiệm trở thành TRUE, bạn có thểassertive::is_whole_number(x, tol = 200 * .Machine$double.eps)

Dù sao, tôi xác nhận rằng IMO khẳng định vẫn là giải pháp tốt nhất.

Dưới đây là bản đại diện cho [CẬP NHẬT] này.

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

Được tạo vào 2019-07-23 bởi gói reprex (v0.3.0)

[CŨ] ================================================= ==================

IMO giải pháp tốt nhất đến từ assertivegói (hiện tại, giải quyết tất cả các ví dụ tích cực và tiêu cực trong chuỗi này):

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

Được tạo vào 2019-07-23 bởi gói reprex (v0.3.0)



0

Một lần cũng có thể sử dụng dplyr::near:

library(dplyr)

near(a, as.integer(a))

Nó áp dụng cho bất kỳ vectơ nào avà có tham số dung sai tùy chọn.


-3

Tôi không chắc bạn đang cố gắng hoàn thành điều gì. Nhưng đây là một số suy nghĩ:
1. Chuyển đổi thành số nguyên:
num = as.integer(123.2342)
2. Kiểm tra xem một biến có phải là số nguyên hay không:
is.integer(num)
typeof(num)=="integer"


Tôi chỉ đảm bảo rằng người dùng nhập một số thích hợp - chúng ta đang nói về số lượng "đối tượng", có thể chỉ là một số nguyên.
Roman Luštrik
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.