Очень часто, в разрабатываемых нами программах реализуется работа с деньгами. Нетрудно догадаться, что отвечающий за это код должен быть хорошо отлажен и защищен от ошибок. Но иногда могут возникнуть такие ошибки, которые заметить очень сложно, а когда они будут замечены - приложение может уже работать у клиента. Одной из таких ошибок является использования класса Float для хранения и проведения операций с финансовой информацией. Эту ошибку часто совершают начинающие разработчики, которые еще не знают, что у класса Float есть проблемы с округлением чисел.

Проведем простой эксперимент:

System.out.println(0.9f - 0.8f);

Можно ожидать, что приведенный код выведет на консоль “0.1″, но на самом деле мы видим “0.099999964″. Это число может быть выведено на страницу счета, что уже плохо. Но самое страшное, что в процессе округления, часть суммы может быть потеряна.

Класс позволяет производить округление с помощью различных алгоритмов:

RoundingMode:
UP          - округление от нуля
DOWN        - округление к нулю
CEILING     - округление в сторону +∞
FLOOR       - округление в сторону -∞
HALF_UP     - округление от нуля, если дробная часть >= 0.5
HALF_DOWN   - округление от нуля, если дробная часть = 0.5
HALF_EVEN   - как и ROUND_HALF_UP, только в случае эквивалентности расстояния
               до соседей - округление выполняется в сторону четного числа
UNNECESSARY - округление не производится

Часто, если округление производится в операциях по выплате денег клиентам, используют округление ROUND_DOWN и ROUND_UP для выставления счетов. Для продолжения вычислений с округленным числом используют ROUND_HALF_EVEN, так как этот алгоритм обеспечивает наибольшую точность.

Класс  - немодифицируемый, поэтому такие операции как setScale() - возвращают новый объект класса .

Пример округления значения:

System.out.println("UP: " + new (1.5f).setScale(0, RoundingMode.UP));
System.out.println("HALF_UP: " + new (1.5f).setScale(0, RoundingMode.HALF_UP));
System.out.println("HALF_DOWN: " + new (1.5f).setScale(0, RoundingMode.HALF_DOWN));
System.out.println("HALF_EVEN: " + new (1.5f).setScale(0, RoundingMode.HALF_EVEN));
Результаты:
UP: 2
HALF_UP: 2
HALF_DOWN: 1
HALF_EVEN: 2

Но не стоит расслабляться - привденный ниже код также возвращает “0.099999964237213134765625″, как и код, приведенный в начале:

System.out.println(new (0.9f).subtract(new (0.8f)));

Поэтому, если мы считаем копейки, которые должны выставить в счете, необходимо изменить код:

System.out.println(new (0.9f).subtract(new (0.8f)).setScale(2, RoundingMode.UP));

И вот теперь мы можем взять у клиента эти 10 копеек!

Связанные записи