Стендап Сьогодні 📢 Канал в Telegram @stendap_sogodni
🤖🚫 AI-free content. This post is 100% written by a human, as is everything on my blog. Enjoy!04.06.2023
Зберігайте гроші в цілочисельних значеннях
Ми в Сінтрі зберігаємо всі грошові суми у цілочисельній формі, тобто як значення в копійках. Це важливо не тільки для проведення арифметичних операцій, а й для збереження та відтворення значень. Дробові числа ніколи не можна використовувати для точних обчислень, спробую пояснити, чому.
На перший наївно-освічений погляд, яка там різниця — адже 1.23 гривні
це теж саме що й 123e-2
, в науковій нотації. Але це тільки абстракція про людські очі. Насправді дробові числа зберігаються у двійковому вигляді, з двійковою експонентою, а ніяк не десятковою. (З 2008 існує десятковий стандарт, але на практиці його ніде не побачиш.)
Чому це має значення? Для цілих чисел двійкове зображення нічого не змінює, та ми можемо практично про нього не знати. Але з дробами все не те що гірше, воно дуже погано. Десяткові дроби, як правило, не перекладаються в красиві та акуратні двійкові дроби (пояснення виходить за рамки цього короткого оповідання.) Навпаки, типовий десятковий дріб стає періодичним двійковим. Так що ті 1.23
гривні у двійковій системі мають вигляд 1.00111010111...
. При запису нескінченного дробу в скінченну памʼять ми обовʼязково втрачаємо точність.
При цьому при перетворенні округленого значення в десятковий вигляд ми можемо отримати вже інше значення: 1.23046875
. Принаймні все двійкові дроби стають скінченними десятковими (хоча це мало нам допомагає.) Також добре, що такий десятковий дріб вже нормально вкладається у двійковий… якщо його не округлити в десятковому вигляді. Також точність втрачається на будь-якій арифметичній операції, навіть на додаванні.
Так на кожній операції значення поступово псуються, або, як то кажуть, гниють. Це не якесь теоретичне занепокоєння — ми стикнулись з ним вже на перших місяцях внутрішнього тестування. Після цього всю математику перевели на цілі числа, які стають дробами тільки для відображення їх в інтерфейсі.
Звісно, ми не можемо зберігати дробові значення копійок. Проте, як виявляється, реальні дробові копійки не існують. Та, хоч теоретично можна, скажімо, рівно поділити 1000 гривень на 7 днів та забюджетувати 142.85714286… на день, практично це не має жодного сенсу; фактично ми округляємо до 142.86 та коректуємо останній день, щоб вписатися в початкову суму.