>
>
>
V6068. Suspicious use of BigDecimal cla…


V6068. Suspicious use of BigDecimal class.

Анализатор обнаружил использование класса BigDecimal, которое может вести себя не так, как ожидал разработчик.

Анализатор выдает предупреждения в следующих ситуациях:

1. Вызов конструктора, аргументом которого является число с плавающей точкой.

Пример такого использования:

BigDecimal bigDecimal = new BigDecimal(0.6);

Про использование таким образом конструктора есть несколько примечаний в документации класса.

Если не вдаваться в подробности, то созданный таким образом объект будет иметь значение 0.59999999999999997779553950749686919152736663818359375 вместо 0,6. Это связано с невозможностью точного представления числа с плавающей точкой.

А ведь BigDecimal прежде всего необходим для вычислений с крайне высокими требованиями к точности. И примеру, есть ПО, в котором от точности вычислений может зависеть человеческая жизнь (ПО для самолетов, ракет или для медицинского оборудования). Поэтому погрешность даже в 30 разряде после запятой может сыграть свою роль.

Чтобы этого избежать, необходимо создавать объект BigDecimal одним из следующих способов:

BigDecimal bigDecimal1 = BigDecimal.valueOf(0.6);
BigDecimal bigDecimal2 = new BigDecimal("0.6");

2. Вызов метода 'equals', так как вполне вероятно имелся ввиду метод 'compareTo'.

Принято считать, что для сравнения объектов нужно вызывать метод 'equals'. Тут не поспорить!

И когда разработчик работает с объектом этого класса, то может считать, что он просто работает с объектом, который может содержать очень большое вещественное число. И вызывая метод 'equals', подразумевает эквивалентность сравниваемых чисел.

В таком случае, следующий фрагмент кода может удивить разработчика:

BigDecimal bigDecimal1 = BigDecimal.valueOf(0.6);
BigDecimal bigDecimal2 = BigDecimal.valueOf(0.60);
....
if (bigDecimal1.equals(bigDecimal2)) // false
{
  // code
}

Нюанс кроется в том, что при сравнении через метод 'equals' сравнивается не только значение, но и количество значащих чисел после запятой. Как раз этого разработчик может и не ожидать. Чтобы сравнивать числа без учета значащих чисел после запятой необходимо использовать метод 'compareTo':

BigDecimal bigDecimal1 = BigDecimal.valueOf(0.6);
BigDecimal bigDecimal2 = BigDecimal.valueOf(0.60);
....
if (bigDecimal1.compareTo(bigDecimal2) == 0) // true
{
  // code
}

Данная диагностика классифицируется как:

  • CERT-NUM10-J