О авторе и Эти ноты
За последние три года я работал в Fintech Companies, и я часто вижу, что разработчики JavaScript пытаются использовать только цифры или строки (например, https://github.com/mikemcl/bignumber.js ) с денежными ценностями. Я думаю, что это неправильный путь, а строки или цифры не очень хорошо подходят для финансовых приложений. Но кто-то, вероятно, может спросить, почему? В серии статей я попытаюсь описать почему.
Введение
Округление – очень простой, но глубокий вопрос. Что js приносит нам, когда мы говорим о математических операциях? Да, у нас есть математический объект, который приносит нам методы круглых ценностей.
Math.round(5.5) // => 6 Math.trunc(5.5) // => 5 Math.floor(5.5) // => 5 Math.ceil(5.5) // => 6
Но в чем проблема? Ну, когда мы говорим о округле, мы говорим о преобразовании некоторого количества из большей точности до меньшей точности.
Например, у вас есть функция, которая заканчивается ценностью доллара, такое как $ 7.112312, поэтому ценность округления с центами составит 7,11 доллара, что менее точно.
Итак, когда мы раунд, мы хотим, чтобы наш алгоритм минимизировать влияние потерянных ценностей (например, наших центов).
Вы можете сказать: «Это совсем не важно, это всего лишь 1 цент. Ты шутишь, что ли?” ; Ну, для тех, кто не заинтересован в деталях, просто проверьте https://github.com/frolovdev/easymoney Отказ
Для других, кто заинтересовал, не на самом деле, дай мне сек
Какое влияние может округлить?
Предположим, вы являетесь инвестором – действительно большой инвестор, другими словами, менеджер по хедж-фонду, и вы решите вложить свои $ 200, покупая некоторые акции. В нашей модели цена акций зависит только от одного принципа: чем больше людей, которые хотят купить акции, тем больше цена (цена) акции имеют и наоборот.
Двигаясь, мы притворяемся, что цена на акции колеблется каждую секунду со случайными значениями от -0,05 до +0,05 (вы покупаете и продаете).
Давайте рассмотрим немного кода. Вы не хотите думать о округлении и решили отрезать все после третьего десятилетнего времени. В математике это называется усеченным или округлением к нулю, но Math.trunch в JS не дает нам возможность решить, сколько мы хотим, поэтому я создал реализацию ручной работы с 3 десятиками.
function truncate(n) {
return parseInt(n * 1000, 10) / 1000;
}
Просто сдвигая десятичную точку на три места вправо при умножении на 1000, мы получаем целочисленную часть для результата. И сдвиг десятичную точку три места, оставленные при разделении на 1000.
Следующий шаг, принесите наши два экспериментальных значения, один для отслеживания фактического значения ваших акций после завершения симуляции, а другой для значения ваших акций после того, как вы усечали до трех десятичных знаков на каждом шаге.
let actualValue = 200; let truncatedValue = 200;
Теперь создайте нашу модель и займите 100000 секунд. Это около 1,5 дня. За каждую секунду генерируйте случайное значение от -0,05 до 0,05, а затем обновите фактическое значение и усеченное значение.
function truncate(n) {
return parseInt(n * 1000, 10) / 1000;
}
let actualValue = 200;
let truncatedValue = 200;
// just generate random value between -0.05 and +0.05
function generateNumber() {
return Number((Math.random() * (0.05 + 0.05) - 0.05).toFixed(10));
}
// make 1000000 operations in for loop
for (let i = 0; i < 1000000; i++) {
// rand fluctuation
const randFluctuation = generateNumber();
// real value after buy or sell
actualValue = actualValue + randFluctuation;
// truncated value
truncatedValue = truncate(truncatedValue + randFluctuation);
}
// log resulted values
console.log(actualValue);
console.log(truncatedValue);
Вот мой пример (вы можете запустить симуляцию в вашем браузере и получить свои собственные результаты).
Работа с реальными ценностями, вы зарабатываете 13 долларов, но с усечением вы обанкротились!
Давайте повторно запустим симуляцию, но с математическим округлением.
// round implementation
(function() {
function decimalAdjust(type, value, exp) {
if (typeof exp === 'undefined' || +exp === 0) {
return Math[type](value);
}
value = +value;
exp = +exp;
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
return NaN;
}
value = value.toString().split('e');
value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
}
if (!Math.round10) {
Math.round10 = function(value, exp) {
return decimalAdjust('round', value, exp);
};
}
if (!Math.floor10) {
Math.floor10 = function(value, exp) {
return decimalAdjust('floor', value, exp);
};
}
if (!Math.ceil10) {
Math.ceil10 = function(value, exp) {
return decimalAdjust('ceil', value, exp);
};
}
})();
let actualValue = 200;
let truncatedValue = 200;
function generateNumber() {
return Number((Math.random() * (0.05 + 0.05) - 0.05).toFixed(10));
}
for (let i = 0; i < 1000000; i++) {
const randFluctuation = generateNumber();
actualValue = actualValue + randFluctuation;
truncatedValue = Math.round10(truncatedValue + randFluctuation, -4);
}
console.log(actualValue);
console.log(truncatedValue);
Теперь все становится лучше, но мы теряем центы. И это также может быть проблемой. Мы описываем, как справиться с этой проблемой в последующих главах.
Вы также можете прочитать о Ванкувер фондовая биржа которые уселили общее значение показателя до трех десятичных знаков вместо округления. Ошибки округления даже привели к потере жизни: http://www-users.math.umn.edu/~arnold/disasters/patriot.html.
Нижняя линия является округлением важно, а застройщики несут ответственность за то, что являются общими вопросами и как с ними разобраться. В следующей главе мы пытаемся глубоко погружаться в различные алгоритмы округления и выяснить различия между ними.
Не стесняйтесь задавать вопросы, чтобы выразить любое мнение и обсудить с вашей точки зрения. Поделиться, подписаться и сделать код, а не войну. ❤ ️
Оригинал: “https://dev.to/frolovdev/why-rounding-is-more-important-than-you-think-134j”