ตรวจสอบว่าตัวเลขเป็นจำนวนเต็มหรือไม่


106

ฉันประหลาดใจที่ได้รู้ว่า 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)นำไปใช้อย่างถูกต้องผลของการนำไปใช้กับจำนวนเต็มจะเป็นจำนวนเต็มเสมอ ...
Stephen

ดูคำถามที่พบบ่อยใน R cran.r-project.org/doc/FAQ/…
Richie Cotton

5
> check.integer (9.0) [1] TRUE ไม่ใช่
Peng Peng

@PengPeng, VitoshKa แก้ไขสิ่งนี้ในคำตอบที่ยอมรับ
Roman Luštrik

4
ฉันคิดว่ามีความสับสนเกี่ยวกับแนวคิดทางคณิตศาสตร์และการคำนวณของจำนวนเต็ม ฟังก์ชั่นis.integerตรวจสอบแนวคิดการคำนวณcheck.integerฟังก์ชันผู้ใช้ตรวจสอบมุมมองทางคณิตศาสตร์
João Daniel

คำตอบ:


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

@BenBolker การจับที่ดีมันใช้ได้กับการรบกวนในเชิงบวกฉันคิดว่า ฉันเปลี่ยนเป็นทางเลือกอื่นควรใช้งานได้
เจมส์

2
@ เจมส์ฉันคิดว่ามันควรจะmin(abs(c(x%%1, x%%1-1))) < tolเป็นabs(min(x%%1, x%%1-1)) < tolอย่างอื่นแทนที่จะเป็นอย่างอื่นคุณจะได้รับFALSEสำหรับจำนวนเต็มใด ๆ ...
Cath

3
เกิดอะไรขึ้นas.integer(x) == x? จะไม่ปฏิเสธ 3 หรือ 3.0 ตามที่ต้องการis.integer(x)และจะจับ 3.1
Gabi

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 จะส่งคืนผลลัพธ์ของการประเมินครั้งล่าสุดโดยอัตโนมัติ
Gavin Simpson

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

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

นอกจากนี้ฟังก์ชันเช่นroundจะส่งคืนจำนวนเต็มที่ประกาศซึ่งเป็นสิ่งที่คุณกำลังทำ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

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

4
@VitoshKa รักคำตอบของคุณ! แม้ว่าจะมีจุดหนึ่งที่คุณพลาดไป แต่ตัวเลขเชิงลบที่ไม่มีจุดทศนิยมก็เป็นจำนวนเต็มเช่นกัน) ฉันแก้ไขโค้ดของคุณตามนั้น
Mehrad Mahmoudian

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 !! [BTW มันน่าหงุดหงิดมากที่ R ไม่แสดงผลลัพธ์ของการคำนวณเริ่มต้นเป็น 2.0 เพื่อแสดงว่าค่านั้นมีส่วนประกอบทศนิยม) ดู ... stackoverflow.com/questions/1535021/…
John

6

จากHmisc::spss.get:

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

ตัวเลือกที่ปลอดภัยกว่ามาก IMHO เนื่องจาก "ข้าม" ปัญหาความแม่นยำของเครื่อง ถ้าคุณพยายามที่คุณจะได้รับis.integer(floor(1)) FALSEBTW จำนวนเต็มของคุณจะไม่ถูกบันทึกเป็นจำนวนเต็มหากมี.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] ด้านล่างนี้ฉันพบว่ามันได้ผลเพราะฉันใส่ตัวเลขทั้งหมดไว้ในเวกเตอร์อะตอมเดียว หนึ่งในนั้นคือตัวละครดังนั้นทุกคนจึงกลายเป็นตัวละคร

หากเราใช้รายการ (ดังนั้นการบีบบังคับจะไม่เกิดขึ้น) การทดสอบทั้งหมดจะผ่านอย่างถูกต้อง แต่อย่างใดอย่างหนึ่ง: 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

สร้างเมื่อ 2019-07-23 โดยแพ็คเกจ reprex (v0.3.0)

[เก่า] =============================================== ==================

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

สร้างเมื่อ 2019-07-23 โดยแพ็คเกจ reprex (v0.3.0)


0

หากคุณไม่ต้องการที่จะเขียนฟังก์ชั่นของคุณเองลองcheck.integerจากแพคเกจinstallr ปัจจุบันใช้คำตอบของ VitoshKa

ลองใช้check.numeric(v, only.integer=TRUE)จาก package varhandleซึ่งมีประโยชน์ในการเป็น vectorized



-3

ฉันไม่แน่ใจว่าคุณพยายามทำอะไรให้สำเร็จ แต่นี่คือความคิดบางส่วน:
1. แปลงเป็นจำนวนเต็ม:
num = as.integer(123.2342)
2. ตรวจสอบว่าตัวแปรเป็นจำนวนเต็มหรือไม่:
is.integer(num)
typeof(num)=="integer"


ฉันแค่ตรวจสอบให้แน่ใจว่าผู้ใช้ป้อนตัวเลขที่เหมาะสม - เรากำลังพูดถึงจำนวน "หัวเรื่อง" ซึ่งอาจเป็นจำนวนเต็มเท่านั้น
Roman Luštrik
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.