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
}

Найденные ошибки

Проверено проектов
364
Собрано ошибок
13 504

А ты совершаешь ошибки в коде?

Проверь с помощью
PVS-Studio

Статический анализ
кода для C, C++, C#
и Java

goto PVS-Studio;