Как в Java сравнить 2 вещественных числа на равенство?
У меня есть 2 вещественных числа, например типа double . Я хочу их сравнить на равенство с заданной точность. Как правильно выполнять такое сравнение? Пока в голову приходит такой вариант:
double x, y; . public boolean isEqual(double x, double y, double eps)
Кажется, что в Java должны быть встроенные способы сравнить 2 вещественных числа. Такие существуют?
Отслеживать
13.7k 12 12 золотых знаков 43 43 серебряных знака 75 75 бронзовых знаков
задан 26 ноя 2017 в 9:42
7,175 9 9 золотых знаков 37 37 серебряных знаков 66 66 бронзовых знаков
ваш вариант самый правильный, метод только сделайте статическим и, возможно, напишите перегрузку со стандартным эпсилоном. и ещё возможно, можно написать другой метод, сравнивающий относительные отклонения вместо абсолютных
26 ноя 2017 в 10:29
4 ответа 4
Сортировка: Сброс на вариант по умолчанию
Вообще, это довольно интересный вопрос.
Да, в общем случае всегда рекомендуется использовать что-то вроде:
bool isEqual = fabs(a1 – a2)
Но более интересный вопрос, какое значение для epsilon использовать.
К примеру, в C++ в float.h есть константа FLT_EPSILON , равная 1E-5 . Всё, можно такое же значение использовать, да?
Вполне, если числа большие. Но если у вас число в промежутке [0;1], то начинаются проблемы. Точность вычисления будет соизмерима с фактическим значением, что приведёт к тому, что на такое сравнение нельзя будет положиться.
Относительный эпсилон
Для сравнения чисел можно руководствоваться правилом:
Для сравнения a1 и a2 вычисляем diff = fabs(a1-a2). Если diff меньше ,чем n% от max(abs(a1), abs(a2)), тогда a1 и a2 можно считать равными.
public static bool almostEqualRelative(float a, float b, float maxRelDiff = FLT_EPSILON) < // находим разницу float diff = fabs(a - b); A = fabs(a); B = fabs(b); // находим большее float largest = (b >a) ? b : a; if (diff
Более сложно и подробней про это можно почитать в этой занятной статье.
Как сравнивать 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
При сравнении значений типа 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
Есть лаба где надо сравнить 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 нужно сравнить особым образом". Почему бы их не сравнить как другие числа? Типа из-за того, что на каких-то там мегавеличинах будет неточность?
ты только представь себе размеры. Вот если будет задача учёта всех звёзд во вселенной. ну бред же какой-то.