О культе карго и хранении денег

Posted by Марк Мельник on November 15, 2012

Вы должно быть знаете о культе карго (cargo cult)? Если нет — в Википедии есть замечательная статья. Культом карго также стало модно называть любое подражание без понимания сути. Члены культа карго подражают человеку или группе людей, которые добились успеха в чем-либо, рассчитывая на то, чтобы добиться аналогичных результатов от своего повторения.

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

Если спросить — Чем тушить пожар? — Большинство не задумываясь ответят — Водой. На самом же деле не всякий пожар можно тушить водой. Например, нельзя тушить водой электротехнику, нельзя потушить водой горючие жидкости, например, бензин или керосин и т.д. Водой также нельзя тушить воспламенившиеся щелочные металлы и много-много чего прочего.

А теперь отойдем от философствований (их я очень люблю, но блог не о том) и вернемся к теме разработки ПО. Сразу расскажу вам предысторию, почему у меня возникла идея написания такой статьи.

Недавно у меня возник спор с одним человеком. Он уверенно заявил, что деньги следует хранить в копейках. — В копейках, — переспросил я, — а в чем профит от этого? Человек замялся и в ответ выдал что-то вроде «Так все говорят.».

Делать что-то потому, что так делают «все» — культ карго. Невольно вспоминается несколько грубая поговорка: «Миллиарды мух не могут ошибаться — в говне определенно что-то есть!». Если бы меня интересовало мнение большинства, то я программировал бы на PHP, а не на Ruby, просто потому, что PHP более популярен, а вместо разработки крутых нагруженных проектов я бы «создавал» сайты-визитки. Важно не мнение большинства или вообще чье-либо мнение, а истина.

Итак, в чем истина, брат?

Истина в том, что деньги не нужно хранить в копейках. Можно, но не нужно. Нет такой необходимости. Вы можете хранить деньги в рублях, копейках, «милликопейках», «микрокопейках» — в чем угодно! Суть заключается в том, что деньги НЕ нужно хранить числом с плавающей точкой. Почему? — читай ниже.

1.

16.8 * 1.1 = 16.8 + 1.68 = 18.48 Верно?

А вот и неверно!

16.8 * 1.1 == 18.48 #=> false
16.8 * 1.1 #=> 18.480000000000004

А вот еще более простой пример:

1.0 - 0.9 #=> 0.09999999999999998

Мы не можем выполнять точные сравнения!

  1. Числа с плавающей точкой очень ненадежны. Знающие люди поговаривают, что результат операций с ними может зависеть от температуры (реально проводился такой эксперимент) — напоминает генерацию случайных чисел. Кроме того, не стоит забывать о проблеме округления чисел с плавающей точкой. Количество знаков после точки ограничено, а потому, хотите вы того или нет — происходит округление. При каждом новом действии с таким числом ошибка накапливается.

«Хранить деньги в копейках» — это означает хранить количество денег целым числом с точностью до копейки. Вместо 1000.57 («одна тысяча рублей и пятьдесят семь копеек») мы храним 100057 («сто тысяч пятьдесят семь копеек»). Разумеется, при различных операциях мы теряем дробную часть, но это прогнозируемо и не так страшно, особенно, если вспомнить то, что я говорил выше — вы не обязаны хранить количество денег с точностью до копейки. Сумму в 1000 руб. 57 коп. вы можете хранить как 100057000 — с точность до 1/1000 копейки, или 100057000000 — 1/1000000 копейки. Я думаю, что точности до 1/1000 копейки вам хватит с лихвой. Потеря нескольких десятков рублей на миллиардных оборотах — это мелочь. Работать с идеальной точностью невозможно! Помните об иррациональных числах.

5 / 3 #=> 1
5.0 / 3 #=> 1.6666666666666667

Потери будут всегда. Ваша задача, как разработчиков — сделать их минимальными и более-менее прогнозируемыми.