В интересах создания межплатформенного кода я хотел бы разработать простое финансовое приложение в JavaScript. Требуемые вычисления включают сложный процент и относительно долгие десятичные числа. Я хотел бы знать, каких ошибок избежать, чтобы использование JavaScript сделало этот тип математики — если это возможно вообще!
Вероятно, вам следует масштабировать десятичные значения на 100, а все денежные значения представлять в целых центах. Это позволит избежать проблем с логикой и арифметикой с плавающей точкой. В JavaScript нет десятичного типа данных - единственным числовым типом данных является плавающая точка. Поэтому обычно рекомендуется работать с деньгами в виде 2550
центов вместо 25.50
долларов.
Рассмотрим это на JavaScript:
var result = 1.0 + 2.0; // (result === 3.0) returns true
Но:
var result = 0.1 + 0.2; // (result === 0.3) returns false
Выражение 0.1 + 0.2 === 0.3
возвращает false
, но, к счастью, целочисленная арифметика с плавающей точкой является точной, поэтому ошибки десятичного представления можно избежать путем масштабирования1.
Обратите внимание, что хотя множество вещественных чисел бесконечно, только конечное число из них (18 437 736 874 454 810 627, если быть точным) может быть точно представлено форматом JavaScript с плавающей точкой. Поэтому представление остальных чисел будет приближенным к реальному числу2.
1 Дуглас Крокфорд: JavaScript: Хорошие части: Приложение A - Ужасные части (стр. 105).
2 Дэвид Фланаган: JavaScript: The Definitive Guide, Fourth Edition: 3.1.3 Литералы с плавающей точкой (страница 31).
Нет такой вещи, как «точный» финансовый расчет, потому что всего две десятичные дроби, но это более общая проблема.
В JavaScript вы можете масштабировать каждое значение на 100 и использовать Math.round ()
каждый раз, когда может появиться дробь.
Вы можете использовать объект для хранения чисел и включить округление в его прототипы метода valueOf ()
. Примерно так:
sys = require('sys');
var Money = function(amount) {
this.amount = amount;
}
Money.prototype.valueOf = function() {
return Math.round(this.amount*100)/100;
}
var m = new Money(50.42355446);
var n = new Money(30.342141);
sys.puts(m.amount + n.amount); //80.76569546
sys.puts(m+n); //80.76
Таким образом, каждый раз, когда вы используете объект Money, он будет округлен до двух знаков после запятой. Неокругленное значение по-прежнему доступно через m.amount
.
Вы можете встроить свой собственный алгоритм округления в Money.prototype.valueOf ()
, если хотите.