Страницы

Поиск по вопросам

понедельник, 25 ноября 2019 г.

В чем хранить “деньги”? Float / Double


Был на собеседовании, спросили, "в переменной какого типа лучше хранить деньги"
сказал Float, мол скорость, все дела. - забраковали. Ответа на вопрос "почему" не услышал. так вот почему "деньги" нельзя хранить во Float? 
    


Ответы

Ответ 1



Для денег важны "копейки". Потеря любой значащей цифры в финансовой сфере недопустима Поскольку числа хранятся в двоичной системе - почти любое десятичное нецелое число не имеет конечное количество цифр после запятой. Поскольку мы не можем хранить бесконечно большое количество цифр после запятой, часть числа теряется. Простой пример: 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 Добавлено: Что касается подходящих типов (поскольку на вопросе тег Java - пример для него) для хранения финансовых данных, как уже написали в комментариях и соседних ответах есть два подхода: Типы с произвольной точностью (например BigDecimal). В исходники не смотрел но внутри хранение скорее всего происходит или в строках или массивах цифр; Целочисленные примитивные типы (int или long). При этом в переменных финансы хранятс в неделимых единицах измерения (это не всегда копейки/центы, в ряде случаев должны учитываться, например, сотые доли этих единиц) Как всегда выбор должен определяться спецификой задачи. Типы с произвольной точность скорее всего будут обрабатываться медленнее чем примитивы, но в случае с примитивами нужно "помнить" что мы в них храним, чтобы при выгрузке в смежные системы не получить астрономические суммы.

Ответ 2



Немного, наверное, конкретики можно внести без углубления в тонкости вычислений машины:) Тут надо еще уточнение, какие операции будут с деньгами производиться. Для платежей и переводов - достаточен long. А сама сумма - в минорных единицах. Потом что мы не платим десятыми долями копеек/центов. Т.е. для 1 руб. 10 копеек, будем перечислять 110. Хранить также можно в таком же типе. Но уже появляются вопросы, когда надо проводить вычисления. К примеру, насчитат некий процент за месяц. Тут уж типы double/float, как заметили некоторые, могут дават погрешности из-за тонкостей стандарта чисел с плавающей запятой. Но есть хороший выход есть объекты чисел, которые хранят все значения в целых числах. Конкретнее: два целочисленных значения: мантиссу вещественного числа в виде объекта класса большого целочисленного, и неотрицательный десятичный порядок числа типа int. Тут напрашивается пример для Java: класс BigDecimal. Я бы хранил деньги в нем. Ну а если еще углубиться в расчеты, то для всяких операций есть свои стандарты. Например, если рассчитываем пеню, то округление в большую сторону: При пене в 1.123456 руб, получим 1.13. Все просто. Если кто нашел в моем ответе ошибку, пожалуйста, поправьте меня. Я только въезжаю в финансовые расчетные операции.

Ответ 3



Каждый сам решает в чем хранить деньги, но наиболее стабильной версией является использования класса BigDecimal. Преимущества Точность и значность известна Арифметики и сравнение включены Поддерживается в JDK, JDBC и т.д. Неплохая производительность

Комментариев нет:

Отправить комментарий