Überprüfen Sie, ob die Zahl eine Ganzzahl ist


104

Ich war überrascht zu erfahren, dass R keine praktische Funktion hat, um zu überprüfen, ob die Zahl eine Ganzzahl ist.

is.integer(66) # FALSE

Die Hilfedateien warnen :

is.integer(x)testet nicht, ob es x ganzzahlige Zahlen enthält! Verwenden Sie dazu roundwie in der Funktion is.wholenumber(x)in den Beispielen.

Das Beispiel hat diese benutzerdefinierte Funktion als "Problemumgehung"

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

Wenn ich eine Funktion schreiben müsste, um nach Ganzzahlen zu suchen, würde ich, vorausgesetzt ich hätte die obigen Kommentare nicht gelesen, eine Funktion schreiben, die etwas in der Art von geht

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

Wo würde mein Ansatz scheitern? Was wäre deine Arbeit, wenn du in meinen hypothetischen Schuhen steckst?


Ich würde hoffen, dass, wenn round(x)es richtig implementiert wird, das Ergebnis der Anwendung auf eine Ganzzahl immer diese Ganzzahl wäre ...
Stephen


5
> check.integer (9.0) [1] WAHR ist es nicht.
Peng Peng

@PengPeng, VitoshKa hat dies in der akzeptierten Antwort behoben.
Roman Luštrik

4
Ich denke, es gibt eine Verwirrung über mathematische und rechnerische Konzepte der ganzen Zahl. Die Funktion is.integerprüft das Rechenkonzept, die check.integerBenutzerfunktion prüft den mathematischen Gesichtspunkt.
João Daniel

Antworten:


126

Eine andere Alternative besteht darin, den Bruchteil zu überprüfen:

x%%1==0

oder, wenn Sie innerhalb einer bestimmten Toleranz prüfen möchten:

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

1
Funktioniert der Vorschlag zur Toleranzprüfung wirklich? x <- 5-1e-8; x%%1ergibt 0,9999999 (was tol==1e-5zum Beispiel bedeuten würde ), das xist keine ganze Zahl.
Ben Bolker

@ BenBolker Guter Fang, es funktioniert bei positiven Störungen, denke ich. Ich habe es auf eine alternative Lösung geändert, die funktionieren sollte.
James

2
@ James, ich denke, es sollte min(abs(c(x%%1, x%%1-1))) < tolstatt abs(min(x%%1, x%%1-1)) < tolanders sein, Sie werden FALSEfür jede ganze Zahl ...
Cath

3
Was ist los mit as.integer(x) == x? Es wird 3 oder 3.0 nicht ablehnen, wie es is.integer(x)würde, und es wird 3.1 fangen.
Gabi

34

Hier ist eine Lösung mit einfacheren Funktionen und ohne Hacks:

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

Außerdem können Sie auf Wunsch einen ganzen Vektor auf einmal testen. Hier ist eine Funktion:

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

Sie können es ändern, um es *applyim Fall von Vektoren, Matrizen usw. zu verwenden.


11
Das letzte if elsekönnte einfach gemacht werden isTRUE(test). Das ist in der Tat alles, was Sie brauchen, um die if elseKlausel und die returnAnweisungen zu ersetzen, da R automatisch das Ergebnis der letzten Bewertung zurückgibt.
Gavin Simpson

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

3
all(a == as.integer(a))umgeht dieses Problem! '
Alex

Das funktioniert nicht richtig! Schauen Sie sich das folgende Gegenbeispiel an: 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

Das Lesen der R-Sprachdokumentation as.integerhat mehr damit zu tun, wie die Nummer gespeichert wird, als wenn sie praktisch einer Ganzzahl entspricht. is.integertestet, ob die Zahl als Ganzzahl deklariert ist. Sie können eine Ganzzahl deklarieren, indem Sie ein Nachher setzen L.

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

Auch Funktionen wie roundgeben eine deklarierte Ganzzahl zurück, mit der Sie arbeiten x==round(x). Das Problem bei diesem Ansatz ist, was Sie praktisch als Ganzzahl betrachten. Das Beispiel verwendet weniger Präzision zum Testen der Äquivalenz.

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

Abhängig von Ihrer Anwendung können Sie auf diese Weise in Schwierigkeiten geraten.


1
In der zweiten Zeile steht "as.integer testet, ob die Zahl als Ganzzahl deklariert ist." aber ich bin mir ziemlich sicher, dass du "is.integer" gemeint hast. Es ist nur eine Bearbeitung mit einem Zeichen, daher konnte ich sie nicht einfach ändern.
PeterVermont

10

Hier ist ein scheinbar zuverlässiger Weg:

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

Diese Lösung ermöglicht auch Ganzzahlen in wissenschaftlicher Notation:

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

1
Das sieht für mich nicht sehr zuverlässig aus: check.integer(1e4)ist WAHR, während check.integer(1e5)es FALSCH ist.
wch

5
-1 Dies ist schlimmer als is.wholenumberoder eine der anderen Lösungen, die in anderen Antworten angegeben sind. Diese sollten nicht anders sein : check.integer(1e22); check.integer(1e23). Sie können natürlich den regulären Ausdruck ändern, um dies zu beheben, aber dieser Ansatz ist schrecklich. (Kommentar stammt von der Zuschreibung im Installationspaket.)
Joshua Ulrich

1
@PatrickT, ich verstehe. Dies ist das Argument der Standardziffer. Verwenden Sie format(40, scientific = FALSE, digits = 20)stattdessen. Ich habe die Antwort aktualisiert. Danke, dass du es entdeckt hast.
VitoshKa

1
@PatrickT Sie befinden sich im Bereich maschinenabhängiger Rundungsfehler. In dieser Hinsicht ist meine Lösung dieselbe wie die akzeptierte 1.0000000000000001 == 1L [1] TRUE. Aber meine Lösung ist besser, wenn Sie bereits eine Zahl in Zeichenfolgenform erhaltencheck.integer("1000000000000000000000000000000000001") [1] TRUE
VitoshKa

4
@VitoshKa liebte Ihre Antwort! Obwohl es einen Punkt gibt, den Sie verpasst haben, sind negative Zahlen ohne Dezimalstellen ebenfalls ganzzahlig;) Ich habe Ihren Code entsprechend geändert.
Mehrad Mahmoudian

8

Es scheint, dass Sie keine Notwendigkeit sehen, eine gewisse Fehlertoleranz zu berücksichtigen. Es wäre nicht erforderlich, wenn alle Ganzzahlen als Ganzzahlen eingegeben würden. Manchmal sind sie jedoch das Ergebnis von arithmetischen Operationen, die an Genauigkeit verlieren. Beispielsweise:

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

Beachten Sie, dass dies nicht die Schwäche von R ist. Alle Computersoftware haben einige Genauigkeitsgrenzen.


3
Nur für den Fall, dass einige Leute nicht ganz verstehen, was hier passiert ist ... Wenn Sie as.integer (2/49 * 49) eingeben, erhalten Sie 1 !! [Übrigens ist es sehr frustrierend, dass R das Ergebnis der anfänglichen Berechnung nicht als 2,0 darstellt, um darzustellen, dass der Wert eine Dezimalkomponente hat.) Siehe ... stackoverflow.com/questions/1535021/…
John

6

Von Hmisc::spss.get:

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

viel sicherere Option, IMHO, da es das Problem der Maschinengenauigkeit "umgeht". Wenn Sie es versuchen is.integer(floor(1)), werden Sie bekommen FALSE. Übrigens wird Ihre Ganzzahl nicht als Ganzzahl gespeichert, wenn sie größer als der .Machine$integer.maxWert ist, dh standardmäßig 2147483647, also ändern Sie entweder den integer.maxWert oder führen Sie die alternativen Überprüfungen durch ...


1
Wenn x <- sqrt(2)^2, dann all(floor(x) == x, na.rm = TRUE)kehren Sie zurückFALSE
Corrado

3

Sie können einfache wenn Bedingung wie verwenden:

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

1

In R kann durch die Klassenfunktion bestimmt werden, ob eine Zahl numerisch oder ganzzahlig ist. Im Allgemeinen werden alle Zahlen als numerisch gespeichert. Um eine Zahl explizit als Ganzzahl zu definieren, müssen Sie nach der Zahl 'L' angeben.

Beispiel:

x <- 1

Klasse (x)

[1] "numerisch"

x <- 1L

Klasse (x)

[1] "Ganzzahl"

Ich hoffe, das war es, was gebraucht wurde. Vielen Dank :)


0

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

In Bezug auf die [ALTE] Antwort hier unten habe ich festgestellt, dass es funktioniert hat, weil ich alle Zahlen in einen einzelnen Atomvektor gesetzt habe. Einer von ihnen war ein Charakter, also wurde jeder zu einem Charakter.

Wenn wir eine Liste verwenden (daher kommt es nicht zu Zwang), bestehen alle Tests korrekt, bis auf einen : 1/(1 - 0.98), der a bleibt numeric. Dies liegt daran, dass der tolParameter standardmäßig verwendet wird 100 * .Machine$double.epsund diese Zahl bei weitem nicht 50kleiner als das Doppelte ist. Im Grunde genommen haben wir für diese Art von Zahlen auf unsere Toleranz entscheiden!

Also, wenn Sie wollen, dass alle Tests wurden TRUE, können Sieassertive::is_whole_number(x, tol = 200 * .Machine$double.eps)

Wie auch immer, ich bestätige, dass IMO durchsetzungsfähig die beste Lösung bleibt.

Hier unten ein Reprex für dieses [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

Erstellt am 23.07.2019 vom reprex-Paket (v0.3.0)

[ALT] =============================================== ==================

IMO die beste Lösung kommt aus dem assertivePaket (das im Moment alle positiven und negativen Beispiele in diesem Thread löst):

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

Erstellt am 23.07.2019 vom reprex-Paket (v0.3.0)



0

Einmal kann auch verwendet werden dplyr::near:

library(dplyr)

near(a, as.integer(a))

Es gilt für jeden Vektor aund verfügt über einen optionalen Toleranzparameter.


-3

Ich bin mir nicht sicher, was Sie erreichen wollen. Aber hier sind einige Gedanken:
1. In Ganzzahl konvertieren:
num = as.integer(123.2342)
2. Überprüfen Sie, ob eine Variable eine Ganzzahl ist:
is.integer(num)
typeof(num)=="integer"


Ich stelle nur sicher, dass die Benutzer eine geeignete Nummer eingeben - wir sprechen über die Anzahl der "Themen", die nur eine ganze Zahl sein können.
Roman Luštrik
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.