Подтвердить что ты не робот

Java: сравнение двойных значений

Нужно ли быть осторожным при сравнении двойного значения с нулем?

if ( someAmount <= 0){
.....
}
4b9b3361

Ответ 1

Если вы хотите быть очень осторожным, вы можете проверить, находится ли он в пределах одного эпсилона нуля с чем-то вроде

double epsilon = 0.0000001;
if      ( f <= ( 0 - epsilon ) ) { .. }
else if ( f >= ( 0 + epsilon ) ) { .. }
else { /* f "equals" zero */ }

Или вы можете просто округлить свои удвоения до определенной заданной точности, прежде чем разветвляться на них.

Для некоторых интересных деталей сравнения погрешности чисел с плавающей запятой вот статья Брюса Доусона.

Ответ 2

Для равенства: (т.е. == или !=) да.

Для других сравнительных операторов (<, >, <=, >=) это зависит от того, связаны ли вы с крайними случаями, например. то ли < эквивалентно <=, что является другим случаем равенства. Если вы не заботитесь о случаях краев, это обычно не имеет значения, хотя это зависит от того, откуда берутся ваши входные номера и как они используются.

Если вы ожидаете, что (3.0/10.0) <= 0.3 будет оцениваться как true (это может быть не так, если ошибка с плавающей запятой приводит к тому, что 3.0/10.0 оценивается числом чуть больше 0,3, например 0,300000000001), и ваша программа будет плохо себя вести, если она оценит как false - это краевой случай, и вам нужно быть осторожным.

Хорошие численные алгоритмы почти никогда не должны зависеть от случаев равенства и краев. Если у меня есть алгоритм, который принимает в качестве входного значения "x", который является любым числом от 0 до 1, вообще говоря, не имеет значения, есть ли 0 < x < 1 или 0 <= x <= 1. Однако есть исключения: вы должны быть осторожны при оценке функций с точками ветвления или особенностями.

Если у меня есть промежуточная величина y, и я ожидаю y >= 0, и я оцениваю sqrt(y), тогда я должен быть уверен, что ошибки с плавающей запятой не приводят к тому, что y является очень маленьким отрицательным числом и sqrt(), чтобы вызвать ошибку. (Предположим, что это ситуация, когда комплексные числа не задействованы.) Если я не уверен в числовой ошибке, я бы, скорее всего, оценил sqrt(max(y,0)).

Для выражений типа 1/y или log(y) в практическом смысле не имеет значения, является ли y нулем (в этом случае вы получаете ошибку сингулярности), или y - это число очень близко к нулю (в этом случае вы получится очень большое число, величина которого очень чувствительна к значению y) - оба случая являются "плохими" с численной точки зрения, и мне нужно переоценить то, что я пытаюсь сделать, и что поведение, которое я ищу, когда значения y находятся в окрестности нуля.

Ответ 3

В зависимости от того, как вычисляется ваш someAmount, вы можете ожидать некоторого нечетного поведения с float/doubles

В принципе, преобразование числовых данных в их двоичное представление с использованием float/doubles является склонным к ошибкам, потому что некоторые числа не могут быть представлены с помощью мантиса/экспоненты.

Для некоторых подробностей об этом вы можете прочитать эту небольшую статью

Вам следует использовать java.lang.Math.signum или java.math.BigDecimal, особенно для валютных и налоговых вычислений

Ответ 4

Следите за автоматической распаковкой:

Double someAmount = null;
if ( someAmount <= 0){

Бум, исключение NullPointerException.

Ответ 5

Да, вы должны быть осторожны.

Предложение: Один из лучших способов - использовать BigDecimal для проверки равенства/не равенства на 0:

BigDecimal balance = pojo.getBalance();//get your BigDecimal obj

0 != balance.compareTo(BigDecimal.ZERO)

Объяснение:

Функция compareTo() сравнивает этот BigDecimal с указанным BigDecimal. Этим методом два объекта BigDecimal, равные по стоимости, но имеющие разный масштаб (например, 2.0 и 2.00), считаются равными. Этот метод предоставляется в предпочтении индивидуальным методам для каждого из шести boolean операторов сравнения (<, ==, >, >=, !=, <=). Предложенная идиома для выполнения этих сравнений: (x.compareTo(y) <op> 0), где один из шести операторов сравнения.

(Благодаря документации SonarQube)

Математика с плавающей запятой является неточной из-за проблем хранения таких значений в двоичном представлении. Хуже того, математика с плавающей запятой не ассоциативна; нажимайте float или double через ряд простых математических операций, и ответ будет отличаться в зависимости от порядка этих операций из-за округления, которое происходит на каждом шаге.

Даже простые назначения с плавающей запятой не просты:

float f = 0.1; // 0.100000001490116119384765625
double d = 0.1; // 0.1000000000000000055511151231257827021181583404541015625

(Результаты будут зависеть от настроек компилятора и компилятора);

Поэтому использование операторов равенства (==) и неравенства (! =) По плавающим или двойным значениям почти всегда является ошибкой. Вместо этого лучше всего избегать сопоставлений с плавающей запятой. Если это невозможно, вам следует рассмотреть возможность использования одного из чисел с плавающей запятой Java, таких как BigDecimal, которые могут корректно обрабатывать сравнения с плавающей запятой. Третий вариант - смотреть не на равенство, а на то, достаточно ли это значение. Т.е. сравните абсолютное значение разницы между сохраненным значением и ожидаемым значением с допустимой погрешностью. Обратите внимание, что это не распространяется на все случаи (например, NaN и Infinity).

Ответ 6

Если вы не заботитесь о случаях краев, то просто проверьте someAmount <= 0. Это делает цель кода понятной. Если вам все равно, хорошо... это зависит от того, как вы вычисляете someAmount и почему вы тестируете неравенство.

Ответ 7

Проверить значение double или float равным 0, пороговое значение ошибки используется для определения того, находится ли значение около 0, но не совсем 0. Я думаю, что этот метод является лучшим, что я встретил.

Как проверить, является ли double равным нулю?Ответил @William Morrison

public boolean isZero(double value, double threshold){
  return value >= -threshold && value <= threshold;
}

Например, установите порог как 0. как это,

System.out.println(isZero(0.00, 0));
System.out.println(isZero(0, 0));
System.out.println(isZero(0.00001, 0));

Результаты как истинные, истинные и ложные из приведенных выше примерных кодов.

Have Fun @. @