Недавно мы внедрили систему, которая должна обрабатывать значения в нескольких валютах и конвертировать между ними, а также выяснили некоторые сложные вещи.
НИКОГДА НЕ ИСПОЛЬЗУЙТЕ НОМЕРА С ПЛАВАЮЩИМИ ТОЧКАМИ ДЛЯ ДЕНЕГ
Арифметика с плавающей запятой вносит неточности, которые могут быть не замечены, пока они не напортачили. Все значения должны храниться в виде целых чисел или типов с фиксированной десятичной дробью, и если вы решите использовать тип с фиксированной десятичной дробью, убедитесь, что вы точно понимаете, что этот тип делает под капотом (т. Е. Использует ли он внутренне целое число или число с плавающей запятой). тип).
Когда вам нужно сделать расчеты или преобразования:
- Преобразовать значения в число с плавающей запятой
- Рассчитать новое значение
- Округлить число и преобразовать его обратно в целое число
При преобразовании числа с плавающей запятой обратно в целое число на шаге 3, не просто приведите его - используйте математическую функцию, чтобы сначала округлить его. Это обычно будет round
, хотя в особых случаях это может быть floor
или ceil
. Знайте разницу и тщательно выбирайте.
Храните тип числа рядом со значением
Это может быть не так важно для вас, если вы работаете только с одной валютой, но для нас это было важно при работе с несколькими валютами. Мы использовали трехсимвольный код для валюты, такой как 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. Мы смогли сделать это только потому, что код, который работает с валютами, не обязательно должен находиться внутри самого уровня базы данных, поэтому все значения можно сначала преобразовать в память. Другие ситуации, без сомнения, поддаются другим решениям.
И в случае, если я не дал понять раньше, не используйте float!