Числа с плавающей точкой

Что только не хранят программисты во float — деньги, количество и вес, сотни всего. Особенно умиляют координаты — неужели они их реально складывать и вычитать собираются?

Если кто не знает, float — это числа с плавающей точкой, которые не гарантируют точности. Верно, вам никто не обещает, что 0.1 + 0.2 будет равно 0.3. Если говорить грубо, причина в том, что в компьютере нет нецелых чисел — там вообще только нули и единицы.

Если вам надо хранить десятичные дроби, используйте специальные типы данных, которые для этого разрабатывались: Decimal, или что там у вас в языке. Подробнее почитайте на https://0.30000000000000004.com

Понимание организации вычислений с плавающей точкой позволяют выбрать правильный числовой тип для решения конкретной задачи

Какой использовать тип для хранения денег

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

Простой пример: 5.1 переведем в двоичный вид

Целая часть имеет только 3 цифры

 5₁₀ = 1*2²  + 0*2¹  + 1*2⁰ = 101₂

А вот дробная...

.1₁₀ = 0*2⁻¹ + 0*2⁻² + 0*2⁻³ + 1*2⁻⁴ + 1*2⁻⁵ + 0*2⁻⁶ + 0*2⁻⁷ + 1*2⁻⁸ + 1*2⁻⁹...

Если взять только первые 7 цифр (двоичных) после запятой, получится не 0.1, а 0.09375

Что касается подходящих типов для хранения финансовых данных, есть два подхода:

  1. Типы с произвольной точностью (например BigDecimal).

  2. Целочисленные примитивные типы (int или long). При этом в переменных финансы хранятся в неделимых единицах измерения (это не всегда копейки/центы, в ряде случаев должны учитываться, например, сотые доли этих единиц)

Как всегда выбор должен определяться спецификой задачи. Типы с произвольной точностью скорее всего будут обрабатываться медленнее чем примитивы, но в случае с примитивами нужно "помнить" что мы в них храним, чтобы при выгрузке в смежные системы не получить астрономические суммы.

Дополнительные источники

Last updated