Нужно ли быть осторожным при сравнении двойного значения с нулем?
if ( someAmount <= 0){
.....
}
Нужно ли быть осторожным при сравнении двойного значения с нулем?
if ( someAmount <= 0){
.....
}
Если вы хотите быть очень осторожным, вы можете проверить, находится ли он в пределах одного эпсилона нуля с чем-то вроде
double epsilon = 0.0000001;
if ( f <= ( 0 - epsilon ) ) { .. }
else if ( f >= ( 0 + epsilon ) ) { .. }
else { /* f "equals" zero */ }
Или вы можете просто округлить свои удвоения до определенной заданной точности, прежде чем разветвляться на них.
Для некоторых интересных деталей сравнения погрешности чисел с плавающей запятой вот статья Брюса Доусона.
Для равенства: (т.е. ==
или !=
) да.
Для других сравнительных операторов (<
, >
, <=
, >=
) это зависит от того, связаны ли вы с крайними случаями, например. то ли <
эквивалентно <=
, что является другим случаем равенства. Если вы не заботитесь о случаях краев, это обычно не имеет значения, хотя это зависит от того, откуда берутся ваши входные номера и как они используются.
Если вы ожидаете, что (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
находятся в окрестности нуля.
В зависимости от того, как вычисляется ваш someAmount
, вы можете ожидать некоторого нечетного поведения с float/doubles
В принципе, преобразование числовых данных в их двоичное представление с использованием float/doubles является склонным к ошибкам, потому что некоторые числа не могут быть представлены с помощью мантиса/экспоненты.
Для некоторых подробностей об этом вы можете прочитать эту небольшую статью
Вам следует использовать java.lang.Math.signum
или java.math.BigDecimal
, особенно для валютных и налоговых вычислений
Следите за автоматической распаковкой:
Double someAmount = null;
if ( someAmount <= 0){
Бум, исключение NullPointerException.
Да, вы должны быть осторожны.
Предложение: Один из лучших способов - использовать 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).
Если вы не заботитесь о случаях краев, то просто проверьте someAmount <= 0
. Это делает цель кода понятной. Если вам все равно, хорошо... это зависит от того, как вы вычисляете someAmount
и почему вы тестируете неравенство.
Проверить значение 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 @. @