Вы должно быть знаете о культе карго (cargo cult)? Если нет — в Википедии есть замечательная статья. Культом карго также стало модно называть любое подражание без понимания сути. Члены культа карго подражают человеку или группе людей, которые добились успеха в чем-либо, рассчитывая на то, чтобы добиться аналогичных результатов от своего повторения.
Разумеется, подражание не есть плохо, но когда это глупое подражание, подражание без понимания сути, тогда это подражание становится глупостью и может сыграть с подражающим злую шутку. Почему? — Потому, что любое следования заповедям — это глупость. Поведение должно быть ситуативным и осмысленным, а не основываться на каких-либо догмах.
Если спросить — Чем тушить пожар? — Большинство не задумываясь ответят — Водой. На самом же деле не всякий пожар можно тушить водой. Например, нельзя тушить водой электротехнику, нельзя потушить водой горючие жидкости, например, бензин или керосин и т.д. Водой также нельзя тушить воспламенившиеся щелочные металлы и много-много чего прочего.
А теперь отойдем от философствований (их я очень люблю, но блог не о том) и вернемся к теме разработки ПО. Сразу расскажу вам предысторию, почему у меня возникла идея написания такой статьи.
Недавно у меня возник спор с одним человеком. Он уверенно заявил, что деньги следует хранить в копейках. — В копейках, — переспросил я, — а в чем профит от этого? Человек замялся и в ответ выдал что-то вроде «Так все говорят.».
Делать что-то потому, что так делают «все» — культ карго. Невольно вспоминается несколько грубая поговорка: «Миллиарды мух не могут ошибаться — в говне определенно что-то есть!». Если бы меня интересовало мнение большинства, то я программировал бы на PHP, а не на Ruby, просто потому, что PHP более популярен, а вместо разработки крутых нагруженных проектов я бы «создавал» сайты-визитки. Важно не мнение большинства или вообще чье-либо мнение, а истина.
Итак, в чем истина, брат?
Истина в том, что деньги не нужно хранить в копейках. Можно, но не нужно. Нет такой необходимости. Вы можете хранить деньги в рублях, копейках, «милликопейках», «микрокопейках» — в чем угодно! Суть заключается в том, что деньги НЕ нужно хранить числом с плавающей точкой. Почему? — читай ниже.
1.
16.8 * 1.1 = 16.8 + 1.68 = 18.48 Верно?
А вот и неверно!
А вот еще более простой пример:
Мы не можем выполнять точные сравнения!
- Числа с плавающей точкой очень ненадежны. Знающие люди поговаривают, что результат операций с ними может зависеть от температуры (реально проводился такой эксперимент) — напоминает генерацию случайных чисел. Кроме того, не стоит забывать о проблеме округления чисел с плавающей точкой. Количество знаков после точки ограничено, а потому, хотите вы того или нет — происходит округление. При каждом новом действии с таким числом ошибка накапливается.
«Хранить деньги в копейках» — это означает хранить количество денег целым числом с точностью до копейки. Вместо 1000.57 («одна тысяча рублей и пятьдесят семь копеек») мы храним 100057 («сто тысяч пятьдесят семь копеек»). Разумеется, при различных операциях мы теряем дробную часть, но это прогнозируемо и не так страшно, особенно, если вспомнить то, что я говорил выше — вы не обязаны хранить количество денег с точностью до копейки. Сумму в 1000 руб. 57 коп. вы можете хранить как 100057000 — с точность до 1/1000 копейки, или 100057000000 — 1/1000000 копейки. Я думаю, что точности до 1/1000 копейки вам хватит с лихвой. Потеря нескольких десятков рублей на миллиардных оборотах — это мелочь. Работать с идеальной точностью невозможно! Помните об иррациональных числах.
Потери будут всегда. Ваша задача, как разработчиков — сделать их минимальными и более-менее прогнозируемыми.