Как проверить, является ли double целым числом


166

Можно ли это сделать?

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
}

Я знаю , что код , вероятно , ничего подобного не идти, но как же оно делось?



1
Что бы вы получили от этого? doubleи intпредставлены в памяти по-разному, и вы будете использовать один или другой в зависимости от контекста обработки вашей памяти.
Макото

@ Легенда, я бы сделал то же самое, что вы предложили; Вы случайно не знаете, как% 1 сравнивает по эффективности с Math.floor (переменная), предложенная другими пользователями?
Г. Бах

3
@Makoto Это программа для поиска пигаторейских троек. Квадратные корни иногда могут быть двойными, но в то же время они также могут быть интергерами. Вы понимаете, о чем я?
JXPheonix

@JXPheonix: Значения могут быть значениями с плавающей точкой или целыми числами. Имеет смысл.
Макото

Ответы:


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

Это проверяет, совпадает ли округленное значение double с двойным.

Ваша переменная может иметь значение типа int или double и Math.floor(variable)всегда иметь значение типа int, поэтому, если ваша переменная равна, Math.floor(variable)она должна иметь значение int.

Это также не работает, если значение переменной бесконечно или отрицательно бесконечно, следовательно, добавляя «пока переменная не бесконечна» к условию.


3
«Если аргумент равен NaN или бесконечности, или положительному нулю, или отрицательному нулю, то результат совпадает с аргументом». docs.oracle.com/javase/6/docs/api/java/lang/…
Тим

2
@TimSchmelter: хороший улов. Стоит также отметить, что NaN не равен ничему (включая себя), но +/- Inf равно самому себе - так что есть два крайних случая!
maerics

И Скон, и Фуад опубликовали гораздо лучшие ответы.
Джоэл Кристофел

@JoelChristophel: я не согласен. Это хороший способ, поскольку он устраняет риск переполнения типа. Единственное, что мне не понравилось, было утверждение, что переменная была intif, если ifоценивать true.
Вирсавия

@Bathsheba (Double.POSITIVE_INFINITY% 1) == 0 и его отрицательный аналог оба имеют значение false.
Джоэл Кристофель

223

Или вы можете использовать оператор по модулю:

(d % 1) == 0


2
Мне очень нравится простота этого решения. Это легко читать и реализовывать.
Криспи

1
Очень интуитивное решение
Даниэль Сан

3
С точки зрения вычислений, это быстрее, чем Math.rint(d)?
iTurki

2
Да, это хорошо, но обратите внимание, это решение Java, и оно не очень хорошо определено для отрицательного dв C и C ++.
Вирсавия

4
В Sonar возникает проблема «Тесты на равенство не должны выполняться со значениями с плавающей запятой».
Julio D

86

Гуава: DoubleMath.isMathematicalInteger. (Раскрытие: я написал это.) Или, если вы еще не импортируете Guava, x == Math.rint(x)это самый быстрый способ сделать это; rintзаметно быстрее, чем floorили ceil.


3
Не знал о математике. Ты прав. Это намного быстрее, чем Math.floor
Ленни Маркус

Является ли это как-то предпочтительнее примера кастинга Eng.Fouad?
Джоэл Кристофель

@JoelChristophel: Да. Не все числа типа double с целочисленными значениями находятся в диапазоне int или даже long, поэтому тест не будет работать с ними.
Луи Вассерман

Попался. Тогда (d% 1) == 0 все еще действует.
Джоэл Кристофель


6

Попробуйте так,

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

например:

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

следовательно, 12.9 не является целым числом, тем не менее

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

следовательно, 12.0 является целым числом


3

Вот версия для Integerи 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;
    }
}

Чтобы преобразовать Doubleв Integer:

Integer intVariable = variable.intValue();

3

Рассматривать:

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

Это прилипает к ядру Java и позволяет избежать сравнения на равенство между значениями с плавающей запятой ( ==), что представляется неверным. Это isFinite()необходимо, так как rint()будут проходить значения бесконечности.



3

Вот хорошее решение:

if (variable == (int)variable) {
    //logic
}

почему (bool)актерский состав?
xdavidliu

1
@ xdavidliu В этом нет необходимости. Мы можем игнорировать это.
Нитиш

2

Аналогично ответу SkonJeet выше, но производительность лучше (по крайней мере, в Java):

Double zero = 0d;    
zero.longValue() == zero.doubleValue()

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);
}

Более правильная реализация вернула бы false, и вам пришлось бы написать другой метод, который принимает int в качестве аргумента и возвращает true. : D
Альфа

0

Вы можете попробовать следующим образом: получить целочисленное значение типа double, вычесть его из исходного значения double, определить диапазон округления и проверить, является ли абсолютное число нового значения double (без целочисленной части) больше или меньше вашего определенный диапазон если оно меньше, вы можете указать это целочисленное значение. Пример:

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;
}

Если вы присвоите d значение 33.15, метод вернет true. Чтобы получить лучшие результаты, вы можете назначить более низкие значения для testRange (как 0.0002) на ваше усмотрение.


0

Лично я предпочитаю простое решение по модулю в принятом ответе. К сожалению, SonarQube не любит тесты на равенство с плавающей запятой без установки точности округления. Поэтому мы попытались найти более подходящее решение. Вот:

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

Remainder(BigDecimal)возвращает BigDecimalзначение которого является (this % divisor). Если это равно нулю, мы знаем, что с плавающей запятой нет.



Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.