Нещодавно ми впровадили систему, яка повинна обробляти значення в декількох валютах і конвертувати між ними, а також вирішувала кілька речей важким шляхом.
НІКОЛИ НЕ ВИКОРИСТОВУЮТЬСЯ ПЛАТИВНІ НОМЕРИ НА ГРОШІ
Арифметика з плаваючою точкою вносить неточності, які можуть не помітити, поки вони щось не викрутили. Усі значення повинні зберігатися як цілі чи фіксовані десяткові типи, і якщо ви вирішите використовувати фіксований десятковий тип, то переконайтеся, що ви точно розумієте, що цей тип робить під кришкою (тобто чи використовує він внутрішнє ціле чи плаваючу крапку тип).
Коли вам потрібно зробити обчислення або перетворення:
- Перетворити значення у плаваючу точку
- Обчисліть нове значення
- Заокруглете число і перетворіть його на ціле число
Перетворюючи число плаваючої точки назад в ціле число на кроці 3, не просто додайте його - використовуйте математичну функцію, щоб спочатку її округлити. Зазвичай це буде round
, хоча в особливих випадках це може бути floor
або ceil
. Знайте різницю і обережно вибирайте.
Збережіть тип числа поряд із значенням
Це може бути не так важливо для вас, якщо ви обробляєте лише одну валюту, але для нас це було важливо при обробці кількох валют. Ми використовували 3-символьний код для такої валюти, як USD, GBP, JPY, EUR тощо.
Залежно від ситуації, можливо, також буде корисно зберігати:
- Чи є число до або після оподаткування (і яка ставка податку)
- Чи є число результатом перетворення (і з чого воно було перетворене)
Знайте межі точності чисел, з якими ви маєте справу
Для реальних цінностей ви хочете бути точними, як найменша одиниця валюти. Це означає, що у вас немає цін, менших від цента, копійки, єни, фену тощо. Не зберігайте значення з більшою точністю, ніж це без жодної причини.
Внутрішньо ви можете вирішити справу з меншими значеннями, в цьому випадку це інший тип вартості валюти . Переконайтеся, що ваш код знає, що це, і не змішувати їх. Уникайте використання значень з плаваючою комою навіть тут.
Додавши всі ці правила разом, ми вирішили наступні правила. У запущеному коді валюти зберігаються, використовуючи ціле число для найменшої одиниці.
class Currency {
String code; // eg "USD"
int value; // eg 2500
boolean converted;
}
class Price {
Currency grossValue;
Currency netValue;
Tax taxRate;
}
У базі даних значення зберігаються як рядок у такому форматі:
USD:2500
Це зберігає вартість 25,00 доларів. Ми змогли це зробити лише тому, що код, який має справу з валютами, не повинен знаходитися в самому шарі бази даних, тому всі значення спочатку можуть бути перетворені в пам'ять. Інші ситуації, без сумніву, піддаються іншим рішенням.
І якщо я раніше не зрозумів, не використовуйте флоат!