arturgspb
@arturgspb

Как хранить и работать с деньгами в коде и базе данных?

Вопрос решен. Использовать int предпочтительнее и по скорости и по размеру данных, которые могу в нем храниться. Ниже подробности.


Давайте попробуем раз и навсегда обсудить и понять как хранить и работать с денежными суммами.


Я изучил вопрос и понял, что люди разделились на два лагеря:


1) Хранение в int

2) Хранение в decimal


Допустим, что мне достаточно вести биллинг в рублях с точности до копеек.

Хранение в bigint

Плюсы:
  • Нет плавающей точки — меньше неточностей
  • Можно производить стандартные мат. операции и не бояться, что потеряешь где-то копейки
  • mithraen: Мат. операции идут быстрее (От автора вопроса — я проверил. Расчеты ниже)
  • gleb_kudr: Вот международный стандарт по денежным единицам en.wikipedia.org/wiki/ISO_4217

    Там видно, что число знаков после запятой у них может быть разное. А значит для простоты разработки, все стоит хранить в минимальной дробной денежной единице валюты, осущеставляя конвертацию при выводе (т.е. в int)


Минусы:
  • Надо помнить о постоянном умножении/делении на 100


Хранение в Deciamal/Numeric

Плюсы:
  • Храниться в естественном виде
  • Не надо дополнительно париться при выводе


Минусы:
  • При неаккуратной работе (не через bcmath) можно ошибиться при умножении или делении
  • Работа через bcmath медленее
  • У разной валюты разное кол-во знаков поле запятой — если у вас мультивалютная система, будет избыточность данных. Придется делать более 2 знаков после запятой, но они будут нужны не всем
  • Роберт Мартин: «Использовать числа с плавающей точкой для представления денежных сумм — почти преступление»



Призываю всех в обсуждение, а я буду добавлять пункты. Очень хочется покончить с этим вопросом. И в одном и в другом подходе есть неудобные вещи.

Замеры скорости

Примеры приведу на языке php.

Работа с плавающей точкой
<?php
$a = 1.2;
$b = 3.4;

for ($i=0;$i<1000000;$i++) {
    $c = bcdiv($a,$b,2);
}


Запускаем:
arturgspb@debian:/home$ time php 1.php

real    0m3.490s
user    0m3.468s
sys     0m0.020s


Работа с Int
<?php
$a = 11.2;
$b = 3.4;

$a *= 100;
$b *= 100;

for ($i=0;$i<1000000;$i++) {
    $c = $a/$b;

    // Избавляемся от лишних чисел
    $c *= 100;
    $c = (int)$c;
    $c /= 100;
}


Запускаем:
arturgspb@debian:/home$ time php 2.php

real    0m0.562s
user    0m0.540s
sys     0m0.020s


Разница скорости в 6 раз очевидна.
  • Вопрос задан
  • 20982 просмотра
Решения вопроса 1
Пригласить эксперта
Ответы на вопрос 11
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через TM ID
Похожие вопросы
Вакансии с Моего Круга Все вакансии
Заказы с Фрилансим Все заказы