Как правильно сравнивать double в java
При сравнении значений типа double в Java следует быть осторожным из-за того, что внутреннее представление чисел с плавающей точкой может быть не точным. Например, значения, которые должны быть равными, могут отличаться на очень малое значение.
Вместо использования операторов == или != для сравнения значений типа double рекомендуется использовать методы класса Double , такие как equals() или compare() , которые предоставляют более точный способ сравнения чисел с плавающей точкой.
double d1 = 0.1 + 0.2; double d2 = 0.3; if (Double.valueOf(d1).equals(Double.valueOf(d2))) System.out.println("d1 и d2 равны"); >
В этом примере мы сравниваем два значения типа double , которые должны быть равными. Для сравнения используем метод equals() , который возвращает true , если значения равны, и false в противном случае.
Для сравнения двух значений типа double по их относительной близости друг к другу используйте метод compare() :
double d1 = 0.1 + 0.2; double d2 = 0.3; if (Double.compare(d1, d2) == 0) System.out.println("d1 и d2 близки"); >
Этот метод возвращает 0, если значения равны, 1, если первое значение больше второго, и -1, если первое значение меньше второго. Мы проверяем, равны ли значения, используя == 0
Как сравнивать double java
Сравнение значений типа double в Java может быть несколько запутанным из-за погрешности вычислений с плавающей точкой. Рекомендуется сравнивать значения типа double с использованием заранее заданного уровня точности:
double x = 1.234; double y = 1.235; double epsilon = 0.0001; // уровень точности if (Math.abs(x - y) epsilon) System.out.println("Значения равны"); > else System.out.println("Значения не равны"); >
Здесь мы используем метод Math.abs() , чтобы получить абсолютное значение разницы между x и y . Если это значение меньше заданного уровня точности epsilon , мы считаем, что x и y равны. В противном случае они не равны.
Как сравнить double java
Есть лаба где надо сравнить long и double. При проверке подсказали что long сравнивать с long, long и double нужно сравнить особым образом, все остальные типы приводить к double. Вопрос следующий почему long и double нужно сравнить особым образом? К BigDecimal приводить неверно .
Long.compareTo(x, y)
Добавьте уже новую секцию — java
Хотя просто compare(x, y)
(1) не верно, оба числа должны быть лонг, а тут лонрг и дабл, ты обертку от лонга используешь
(3) просто компайр не бывает
(4) продвижение типов, не?
double val1 = 1.0;
long val2 = (long) val1;
лонг меньше дабл, почему к его к даблу привести вообще не понятно, ошибка может произойти если long_maxvalue. Все равно не понятно как
(6) это косяк сильный, привести дабл к лонг, наоборот можно
(6)
double val1 = 1.5;
long val2 = (long) val1; // равно 1
(9) это понятно, я смотрю на (1)
так как их сравнивать-то «правильно»? Мне вот совсем непонятно, почему их нужно сравнивать как-то по особенному, а не продвигать один тип к другому?
Правильно будет так
long val1 = 1;
double val2 = (double) val1;
«long и double нужно сравнить особым образом, все остальные типы приводить к double»
Так почему long не привести к double?
(11) и я уже все перечитал, не вижу проблемы. цитата «в таком случае у тебя не сработает Long.MAX_VALUE» вот подсказка от проверяющего
(13) походу надо как-то через классы-обёртки сравнивать
(9) double превышает long на много-много порядоков, так как внутри пишется в экспоненциальной форме (много статей в инете о представление плавающей точки на уровне железа). И соответственно у тебя может быть усечение значения.
Более правильно кстати тогда не Long.compare(x,y) брать а Dobule.compare(x,y), хотя на самом деле они оба реализуются на машинном уровне а не байткодом.
(15) я в (9) показал ошибку из другого сообщения, это понятно. Проблема в том что проверяющий не сичтает что перевод в дабл правильное решение. см (13)
jshell> double a = Double.valueOf(Long.MAX_VALUE)
a ==> 9.223372036854776E18
jshell> long b = Long.MAX_VALUE
b ==> 9223372036854775807
jshell> Double.compare(a, b)
$3 ==> 0
(17) А попробуй тоже самое, но long b = Long.MAX_VALUE — 1;
(2) Salesforce
(18) Выдаст точно то же самое:
jshell> double a = Double.valueOf(Long.MAX_VALUE — 1)
a ==> 9.223372036854776E18
jshell> long b = Long.MAX_VALUE
b ==> 9223372036854775807
jshell> Double.compare(a, b)
$3 ==> 0
Просто нужно уяснить что в Double в принципе не может храниться 9223372036854775806 (Long.MAX_VALUE — 1).
происходит потеря точности:
jshell> double d = 9223372036854775806.0
d ==> 9.223372036854776E18
+(20)
jshell> Double d = 9223372036854775806.0
d ==> 9.223372036854776E18
jshell> d.longValue()
$4 ==> 9223372036854775807
+(21)
jshell> Double d = 9.223372036854775E18
d ==> 9.2233720368547748E18
jshell> d.longValue()
$14 ==> 9223372036854774784
Таким образом double может хранить ближайшие числа
9223372036854774784 и 9223372036854775807
(20) напиши как правильно сравнить, пока примерно понятно
(23) Так я и написал Double.compare(x,y)
То что у тебя long будет к примеру Long.MAX_VALUE — 1 оно и будет либо меньше Double.valueOf(Long.MAX_VALUE) либо больше 9223372036854774784. А между этими значениями просто double просто не может содержать значений, ему физически разрядов не хватает для такой точности.
(24) большое тебе спасибо ! ты 1С ник ?
(24) лонги надо сравнивать между собой, а остальные сравнивать через дабл
Короче если по тупому то можно в long засунуть такое число, которое при переносе в double потеряет свою точность.
В то время как классические int прекрасно переносятся и сравниваются с double.
Чтобы сравнить long и double надо знать точность представления типа double на конкретной платформе и привести (округлить) значение.
(27) с точки зрения теории я тебя понимаю, а как на практике это реализовать. На ссылке JavaRush предлагают использовать DigDecimal
вот что получилось
long l1;
long l2;
double d1;
double d2;
if (num1 instanceof Long && num2 instanceof Long)
return Long.compare(l1, l2);
> else if ((num1 instanceof Long && num2 instanceof Double) || (num1 instanceof Double && num2 instanceof Long)) <
// можно в long засунуть такое число, которое при переносе в double потеряет свою точность
BigDecimal b1 = new BigDecimal(«» + num1);
BigDecimal b2 = new BigDecimal(«» + num2);
d1 = num1.doubleValue();
d2 = num2.doubleValue();
return Double.compare(d1, d2);
>
и это ваш великий джава?
2 числа сравнить не может. даже паскаль умеет.
(29) static
Хороший язык java.
Надёжный и простой, как Швейцарские часы.
(33) просто здесь сравнивается класс Number, надеюсь так не используется. Лучше типизировать без компараторов.
(33) — вы так говорите, как будто по ха пе лучше
(35) ты что делфи же лучше всех
(35) фузина зе бэст
(29) вместо преобразования через строку лучше делать
BigDecimal b1 = BigDecimal.valueOf(num1);
(38) сейчас гляну
(38) он так не умеет, по сути я сделал тоже самое только из строки
(38) Проще floatValue() и сравнивать с long
(40) как это не умеет?
https://www.geeksforgeeks.org/bigdecimal-valueof-method-in-java/
(0) Equals предлогали?
так это,мантисса double, это 53 бита,а long это 64
просто,внезапно,регистр сопроцессора это 80 бит и там 64 бита на мантиссу есть,т.к. длинные целые как раз 64 бита.
но типа long double во многих языках нет.
поэтому,можно из long отрезать старшие биты,если они 0,то переводить в double и сравнивать.
если не ноль,то с первого значащего бита отсчитать 53,а оставшийся хвост сраанить с нулем,если он не ноль,то в double такого числа просто нет и можно ничего не сравнивать,если они 0,то переводим в double и срааниваем.
(30) в жабе ещё много чудес есть
(0) читайте про приведение типов
Академические задачи такие академические. Кто-нибудь может мне рассказать практический смысл сей задачи?
(47) просто челу лень книжки читать
Пункт Первый. Java самый лучший язык в мире.
Пункт второй. Если пункт первый не верен, goto Пункт Первый.
(48) дело не в топикстартере, а в «long и double нужно сравнить особым образом». Почему бы их не сравнить как другие числа? Типа из-за того, что на каких-то там мегавеличинах будет неточность?
ты только представь себе размеры. Вот если будет задача учёта всех звёзд во вселенной. ну бред же какой-то.
Быстрое сравнение double
Вчера здесь вышла статья о быстром парсинге double, я зашёл во блог к её автору, и нашёл там ещё один интересный трюк. При сравнении чисел с плавающей точкой особое внимание приходится уделять NaN (восемь лет назад я писал про них подробнее); но если сравниваемые числа заведомо не NaN, то сравнить их можно быстрее, чем это делает процессор!
Положительные double сравнивать очень просто: нормализация гарантирует нам, что из чисел с разной экспонентой больше то, чья экспонента больше, а из чисел с равной экспонентой больше то, чья мантисса больше. Стандарт IEEE 754 заботливо поместил экспоненту в старшие биты, так что положительные double можно сравнивать просто как int64_t.
С отрицательными числами немного сложнее: они хранятся в прямом коде, тогда как int64_t — в дополнительном. Это значит, что для использования целочисленного сравнения младшие 63 бита double необходимо инвертировать (при этом получится -0. < +0., что не соответствует стандарту, но на практике не представляет проблемы). Явная проверка старшего бита и условный переход уничтожили бы всю выгоду от перехода к целочисленному сравнению; но есть способ проще!
inline int64_t to_int64(double x) < int64_t a = *(int64_t*)&x; uint64_t mask = (uint64_t)(a >> 63) >> 1; return a ^ mask; > inline bool is_smaller(double x1, double x2)
a>>63 заполняет все 64 бита копиями знакового бита, и затем >>1 обнуляет старший бит.
Во блоге у Daniel Lemire несколько другой код (той же вычислительной сложности), но мой вариант сохраняет то полезное свойство, что to_int64(0.) == 0
- Высокая производительность
- Ненормальное программирование
- C