Точный финансовый расчет в JavaScript. Что такое Gotchas? - PullRequest
110 голосов
/ 20 мая 2010

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

Ответы [ 6 ]

99 голосов
/ 20 мая 2010

Вы, вероятно, должны масштабировать свои десятичные значения на 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:Хорошие запчасти : Приложение А. Ужасные запчасти (стр. 105) . 2 Дэвид Фланаган: JavaScript: Полное руководство, четвертое издание : 3.1.3 Литералы с плавающей точкой (стр. 31) .

13 голосов
/ 07 августа 2017

Масштабирование каждого значения на 100 является решением. Делать это вручную, вероятно, бесполезно, так как вы можете найти библиотеки, которые делают это для вас. Я рекомендую moneysafe, который предлагает функциональный API, хорошо подходящий для приложений ES6:

const { in$, $ } = require('moneysafe');
console.log(in$($(10.5) + $(.3)); // 10.8

https://github.com/ericelliott/moneysafe

Работает как в Node.js, так и в браузере.

6 голосов
/ 20 мая 2010

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

В 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

Таким образом, каждый раз, когда вы используете денежный объект, он будет представлен как округленный до двух десятичных знаков. Необоснованное значение все еще доступно через m.amount.

Вы можете встроить свой собственный алгоритм округления в Money.prototype.valueOf(), если хотите.

2 голосов
/ 10 июня 2013

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

Решение ниже, пояснение следующее:

Вам нужно подумать о математике, стоящей за этим, чтобы понять это. Вещественные числа, такие как 1/3, не могут быть представлены в математике с десятичными значениями, так как они бесконечны (например, - .333333333333333 ...). Некоторые десятичные числа не могут быть правильно представлены в двоичном виде. Например, 0.1 не может быть правильно представлен в двоичном виде с ограниченным количеством цифр.

Более подробное описание смотрите здесь: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Взгляните на реализацию решения: http://floating -point-gui.de / languages ​​/ javascript /

1 голос
/ 17 июня 2019

Если вы хотите создать действительно точное приложение, вам не следует доверять библиотекам JavaScript. вместо этого вы можете использовать Web-Assembly.

1 голос
/ 25 января 2019

использовать decimaljs ... Это очень хорошая библиотека, которая решает часть проблемы ...

просто используйте его во всех ваших операциях.

https://github.com/MikeMcl/decimal.js/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...