Точное финансовое вычисление в JavaScript. Каковы глюки?

В интересах создания межплатформенного кода я хотел бы разработать простое финансовое приложение в JavaScript. Требуемые вычисления включают сложный процент и относительно долгие десятичные числа. Я хотел бы знать, каких ошибок избежать, чтобы использование JavaScript сделало этот тип математики — если это возможно вообще!

115
задан james_womack 20 May 2010 в 18:04
поделиться

2 ответа

Вероятно, вам следует масштабировать десятичные значения на 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).

102
ответ дан 24 November 2019 в 02:28
поделиться

Нет такой вещи, как «точный» финансовый расчет, потому что всего две десятичные дроби, но это более общая проблема.

В 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 () , если хотите.

6
ответ дан 24 November 2019 в 02:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: