Jak sprawdzić, czy double jest liczbą całkowitą

165

Czy da się to zrobić?

double variable;
variable = 5;
/* the below should return true, since 5 is an int. 
if variable were to equal 5.7, then it would return false. */
if(variable == int) {
    //do stuff
}

Wiem, że kod prawdopodobnie nie działa w ten sposób, ale jak to działa ?

JXPheonix
źródło
1
C #, ale podobny w Javie: stackoverflow.com/a/4077262/284240 ( Integer.MAX_VALUE )
Tim Schmelter
1
Co byś z tego zyskał? doublei intsą reprezentowane w pamięci w różny sposób, a używałbyś jednego lub drugiego w zależności od kontekstu, w jakim operujesz pamięcią.
Makoto
@Legend, zrobiłbym to samo, co sugerowałeś; czy przypadkiem wiesz, jak% 1 porównuje wydajność pod względem wydajności z Math.floor (zmienną) sugerowaną przez innych użytkowników?
G. Bach
3
@Makoto To program do wyszukiwania trójek pigatorejskich. Pierwiastki kwadratowe mogą czasami być podwójne, ale jednocześnie czasami mogą być intergerami. Rozumiesz o co mi chodzi?
JXPheonix
@JXPheonix: Więc wartości mogą być wartościami zmiennoprzecinkowymi lub całkowitymi. Ma sens.
Makoto

Odpowiedzi:

146
if ((variable == Math.floor(variable)) && !Double.isInfinite(variable)) {
    // integer type
}

Sprawdza, czy zaokrąglona w dół wartość double jest taka sama jak double.

Twoja zmienna może mieć wartość int lub double i Math.floor(variable)zawsze mieć wartość int, więc jeśli zmienna jest równa, Math.floor(variable)to musi mieć wartość int.

To również nie działa, jeśli wartość zmiennej jest nieskończona lub ujemna nieskończona, dlatego do warunku dodaje się „tak długo, jak zmienna nie jest nieskończona”.

maxhud
źródło
3
„Jeśli argumentem jest NaN lub nieskończoność lub dodatnie zero lub ujemne zero, to wynik jest taki sam jak argument”. docs.oracle.com/javase/6/docs/api/java/lang/…
Tim Schmelter
2
@TimSchmelter: dobry chwyt. Warto również zauważyć, że NaN nie jest równe żadnemu (w tym sobie), ale +/- Inf jest sobie równe - więc są dwa skrajne przypadki!
maerics
Zarówno Skon, jak i Fouad opublikowali znacznie lepsze odpowiedzi.
Joel Christophel
@JoelChristophel: Nie zgadzam się. To dobry sposób, ponieważ eliminuje ryzyko przepełnienia tekstu. Jedyne, co mi się nie podobało, to stwierdzenie, że zmienna jest wartością, intjeśli ifwartości true.
Batszeba
@Bathsheba (Double.POSITIVE_INFINITY% 1) == 0 i jego ujemny odpowiednik dają wynik fałszywy.
Joel Christophel
222

Lub możesz użyć operatora modulo:

(d % 1) == 0

SkonJeet
źródło
2
Naprawdę podoba mi się prostota tego rozwiązania. Jest zarówno łatwy do odczytania, jak i do wdrożenia.
krispy
1
Bardzo intuicyjne rozwiązanie
Daniel San
3
Jeśli chodzi o obliczenia, czy jest szybszy niż Math.rint(d)?
iTurki
2
Tak, to fajne, ale zauważ dobrze, że jest to rozwiązanie Java i nie jest dobrze zdefiniowane jako negatywne dw C i C ++.
Batszeba
4
W programie Sonar powoduje to problem „Testy równości nie powinny być wykonywane z wartościami zmiennoprzecinkowymi”.
Julio D,
86

Guawa: DoubleMath.isMathematicalInteger. (Ujawnienie: napisałem to.) Lub, jeśli jeszcze nie importujesz guawy, x == Math.rint(x)jest to najszybszy sposób na zrobienie tego; rintjest mierzalnie szybszy niż floorlub ceil.

Louis Wasserman
źródło
3
Nie wiedziałem o Math.rint Masz rację. Jest znacznie szybszy niż Math.floor
Lenny Markus
Czy jest to w jakiś sposób lepsze od przykładu castingowego inż. Fouada?
Joel Christophel
@JoelChristophel: Tak. Nie wszystkie dublety z wartościami całkowitymi mieszczą się w zakresie int, a nawet long, więc ten test na nich nie zadziała.
Louis Wasserman,
Mam cię. Wtedy (d% 1) == 0 jest nadal ważne.
Joel Christophel
20
public static boolean isInt(double d)
{
    return d == (int) d;
}
Eng.Fouad
źródło
6

Spróbuj w ten sposób

public static boolean isInteger(double number){
    return Math.ceil(number) == Math.floor(number); 
}

na przykład:

Math.ceil(12.9) = 13; Math.floor(12.9) = 12;

stąd 12,9 nie jest jednak liczbą całkowitą

 Math.ceil(12.0) = 12; Math.floor(12.0) =12; 

stąd 12,0 jest liczbą całkowitą

Sheldon
źródło
3

Oto wersja dla Integeri Double:

    private static boolean isInteger(Double variable) {
    if (    variable.equals(Math.floor(variable)) && 
            !Double.isInfinite(variable)          &&
            !Double.isNaN(variable)               &&
            variable <= Integer.MAX_VALUE         &&
            variable >= Integer.MIN_VALUE) {
        return true;
    } else {
        return false;
    }
}

Aby przekonwertować Doublena Integer:

Integer intVariable = variable.intValue();
irudyak
źródło
3

Rozważać:

Double.isFinite (value) && Double.compare (value, StrictMath.rint (value)) == 0

To trzyma się rdzenia Javy i pozwala uniknąć porównania równości między wartościami zmiennoprzecinkowymi ( ==), które są uważane za złe. Jest isFinite()to konieczne, podobnie jak rint()wartości nieskończoności.

simon.watts
źródło
3

Najlepszym sposobem jest użycie operatora modułu

if(val % 1 == 0)
Abdul Hafeez Khan
źródło
1
czy możesz dodać więcej wyjaśnień, aby odpowiedzieć? Dzięki!
Shanteshwar Inde
3

Oto dobre rozwiązanie:

if (variable == (int)variable) {
    //logic
}
Nitish
źródło
dlaczego (bool)obsada?
xdavidliu
1
@xdavidliu Nie ma takiej potrzeby. Możemy to zignorować.
Nitish
2

Podobna do odpowiedzi SkonJeeta powyżej, ale wydajność jest lepsza (przynajmniej w Javie):

Double zero = 0d;    
zero.longValue() == zero.doubleValue()
edwardsayer
źródło
1
public static boolean isInteger(double d) {
  // Note that Double.NaN is not equal to anything, even itself.
  return (d == Math.floor(d)) && !Double.isInfinite(d);
}
maerics
źródło
Bardziej poprawna implementacja zwróciłaby false i musiałbyś napisać inną metodę, która przyjmuje int jako argument i zwraca true. : D
alfa
0

możesz spróbować w ten sposób: pobierz wartość całkowitą double, odejmij ją od pierwotnej wartości double, zdefiniuj zakres zaokrąglania i sprawdź, czy liczba bezwzględna nowej wartości double (bez części całkowitej) jest większa lub mniejsza niż twoja zdefiniowany zakres. jeśli jest mniejszy, możesz zamierzyć, że jest to wartość całkowita. Przykład:

public final double testRange = 0.2;

public static boolean doubleIsInteger(double d){
    int i = (int)d;
    double abs = Math.abs(d-i);
    return abs <= testRange;
}

Jeśli przypiszesz d wartość 33,15, metoda zwróci wartość true. Aby uzyskać lepsze wyniki, możesz według własnego uznania przypisać niższe wartości testRange (jako 0,0002).

Salvi94
źródło
0

Osobiście wolę proste rozwiązanie obsługi modulo w przyjętej odpowiedzi. Niestety SonarQube nie lubi testów równości z zmiennoprzecinkowymi bez ustawiania okrągłej precyzji. Dlatego staraliśmy się znaleźć bardziej zgodne rozwiązanie. Oto ona:

if (new BigDecimal(decimalValue).remainder(new BigDecimal(1)).equals(BigDecimal.ZERO)) {
    // no decimal places
} else {
    // decimal places
}

Remainder(BigDecimal)zwraca a, BigDecimalktórego wartość to (this % divisor). Jeśli ta jest równa zero, wiemy, że nie ma zmiennoprzecinkowego.

chaeschuechli
źródło
0

Moje proste rozwiązanie:

private boolean checkIfInt(double 
 value){
 return value - Math.floor(value) == 0;
 }
Mostafa Amer
źródło
-1

Oto rozwiązanie:

float var = Your_Value;
if ((var - Math.floor(var)) == 0.0f)
{
    // var is an integer, so do stuff
}
MOHIT GUPTA
źródło