Тема 70 з 91· Інженерія програмного забезпечення та цифрова доставка
Точний розподіл витрат до цента
Розподіл загальної суми — спільного гранту, рахунку за інфраструктуру, цифри впливу на бюджет — між кількома отримувачами наївним відсотковим обчисленням рутинно дає частини, що не сходяться назад до вихідної суми. Точний розподіл до цента — це розв'язання: цілочисельний/десятковий метод, що працює в найменших одиницях валюти (центах) і гарантує, що частини складаються рівно в ціле, хоч би як нерівно воно ділилося. Кожен інженер-програміст, якому треба звести розподілену суму до копійки — виплата зарплат, видача грантів, перевиставлення рахунків за спільні послуги, — потребує цього шаблону, а не відсотків із плаваючою комою.
Чому це важливо
Це іменований, фундаментальний шаблон корпоративної програмної інженерії: Patterns of Enterprise Application Architecture Мартіна Фаулера (2002) описує Money і Allocate саме тому, що «поділіть 100 $ на трьох» — задача, яку наївний код постійно розв'язує неправильно й мовчки: помилка випливає лише тоді, коли хтось зводить книги й бачить частини на цент менші (або більші) за суму. В економіці охорони здоров'я та фінансовій роботі NHS це не академічне питання: суми впливу на бюджет розподіляють між майданчиками, роками чи директоратами; витрати на спільну інфраструктуру й ліцензії розкладають на відділи за кількістю персоналу чи часткою активності. Кожен такий розподіл має зійтися точно, бо фінансовий директор, якому дають частини, що не складаються в суму, перестає довіряти всій моделі.
Математика
Наївний (хибний) метод:
частина_i = округлити(сума × частка_i / Σ частки) — округлює кожну частину окремо
Точний метод (найбільшого залишку / «largest remainder allocation»):
1. база_i = підлога(сума_найменші_одиниці × частка_i / Σ частки) — лише цілі найменші одиниці (центи)
2. залишок = сума_найменші_одиниці − Σ база_i — зайві центи, завжди < кількості отримувачів
3. роздати по 1 додатковій найменшій одиниці `залишок` отримувачам
із найбільшим дробовим залишком із кроку 1, доки залишок не вичерпається
Результат: Σ частина_i == сума, завжди, за конструкцією.
Точний метод ніколи не округлює частину ізольовано — він округлює весь розподіл як одну операцію, і саме це зберігає інваріант суми.
Розібраний приклад
Поділіть 100,00 $ на три рівні частини (частки = [1, 1, 1]).
Наївний метод: 100,00 $ ÷ 3 = 33,333… $, окремо округлене до найближчого цента дає 33,33 $ кожному отримувачу. Сума: 33,33 $ × 3 = 99,99 $ — один цент зник, і жодна окрема позиція не є настільки «хибною», щоб помітити це оглядом.
Точний метод: база = 33,33 $ для всіх трьох (разом 9 999 найменших одиниць із підлога(10 000 / 3) = 3 333 центи кожному), що лишає залишок 1 цент (10 000 − 9 999). Цей один зайвий цент іде отримувачу з найбільшим дробовим залишком у діленні — хто саме, то внутрішня деталь розв'язання нічиєї, на яку викликач не повинен покладатися. Двоє отримувачів матимуть 33,33 $, а один 33,34 $, і три частини складаються рівно в 100,00 $.
Саме цієї арифметики потребує аналіз впливу на бюджет, коли загальну цифру впливу на бюджет треба розподілити між майданчиками, когортами чи фінансовими роками й звести до опублікованої суми — див. валютно безпечне агрегування витрат щодо супутньої проблеми підсумовування багатьох таких позицій без дрейфу.
Зв'язок з інженерією програмного забезпечення
Це буквально «шаблон Money» з архітектури корпоративного програмного забезпечення — фундаментальний іменований шаблон саме для цього класу помилок, а не одноразовий трюк. Реальні збої фінансового зведення потрапляли у виробництво саме з цього класу помилок: відсоткові розподіли, обчислені в f64, округлені на кожного отримувача й ніколи не звірені з вихідною сумою. Це прямо пов'язано з модулем загальна вартість володіння цього репозиторію, що нині підсумовує звичайні витрати з плаваючою комою за роками й варіантами — та сама дисципліна точності застосовна, коли суму TCO чи впливу на бюджет треба розподілити, а не лише підсумувати.
Підводні камені
- Відсоток-потім-округлення замість найбільшого залишку: розподіл через відсотки з плаваючою комою й окреме округлення кожного отримувача, що посилює похибку округлення й рідко сходиться до суми, особливо з багатьма отримувачами.
- Ігнорування показників найменшої одиниці валют: припущення, що кожна валюта має 2 десяткові знаки — японська єна має 0, деякі валюти мають 3 — саморобний відсотковий розподіл зазвичай жорстко кодує 2 і мовчки ламається для інших валют; точна процедура розподілу читає показник із самої валюти (ISO 4217).
- Повторний розподіл уже розподіленого залишку: повторний запуск процедури розподілу на тому, що лишилося від попереднього розподілу, без перевірок ідемпотентності, що може двічі зарахувати той самий цент тому самому отримувачу.
Джерела
- Fowler M. «Patterns of Enterprise Application Architecture.» Addison-Wesley, 2002 — шаблони
MoneyтаAllocate. - ISO 4217 — стандарт кодів валют і фондів, що визначає показник найменшої одиниці кожної валюти.