Округление чисел в JavaScript

Округление чисел в JavaScript

От автора: довольно часто в JavaScript во время вычислений можно получить число не совсем в нужном нам диапазоне или числа, которые необходимо «почистить» перед дальнейшим использованием. Данные числа округляются в большую или меньшую степень, задаются в определенном диапазоне или «обрезаются» до нужного количества знаком после запятой – все зависит от того, что нужно вам.

Зачем округлять числа?

Один из интересных фактов о JS заключается в том, что данный язык на самом деле не хранит целые числа: числа представлены в двоичном виде с плавающей запятой. Это, в сочетании с тем фактом, что не все дроби можно представить в виде десятичного числа с конечным количеством цифр после запятой, означает, что в JS можно получить следующий результат (с помощью консоли):

0.1 * 0.2;
> 0.020000000000000004

В большинстве случаев с практической точки зрения эта погрешность не будет иметь значения (ошибка одна на 2 квинтиллиона), но все же это немного разочаровывает. Немного странный результат также можно получить при работе с валютами, процентными значениями или единицами измерения размера файла. Чтобы избежать этой неточности, необходимо округлить число или ввести определенное количество знаков после запятой.

Округление имеет много примеров практического применения: к примеру, если пользователь передвигает ползунок элемента range, чтобы не работать с десятичными числами, нам было бы удобнее округлять полученное значение до ближайшего целого.

Округление десятичных чисел

Для урезания десятичных чисел можно использовать методы toFixed() и toPrecision. Оба метода принимают всего один аргумент, который соответственно задает количество «значащих цифр» (т.е. общее количество цифр в числе) или количество знаков после запятой:

Если в toFixed() не задан аргумент, то по умолчанию выставляется 0, т.е. без знаков после запятой, максимальное значение 20.

Если в toPrecision не задан аргумент, число не меняется.

var randNum = 6.25;
randNum.toFixed();
> "6"

Math.PI.toPrecision(1);
> "3"

var randNum = 87.335;
randNum.toFixed(2);
> "87.33"

var randNum = 87.337;
randNum.toPrecision(3);
> "87.3"

Важное замечание

Оба метода toFixed() и toPrecision() возвращают округленное представление строки результата, а не число. Т.е. при «сложении» переменных rounded и randNum будет произведена конкатенация, а не сложение:

console.log(randNum + rounded);
> "6.256"

Если нужно привести результат к числу, воспользуйтесь parseFloat:

var randNum = 6.25;
var rounded = parseFloat(randNum.toFixed(1));
console.log(rounded);
> 6.3

(обратите, что число 5 округлилось в большую сторону, за исключением редких случаев; более подробно чуть ниже.) Также методы toFixed() и toPrecision() бывают полезны, когда необходимо целому числу приписать десятичную часть. Это особенно удобно при работе с валютами:

var wholeNum = 1
var dollarsCents = wholeNum.toFixed(2);
console.log(dollarsCents);
> "1.00"

Обратите внимание, что если в числе больше цифр, чем в аргументе toPrecision, то оно будет записано в научном виде (с мантиссой и порядком):

var num = 123.435
num.toPrecision(2);
> "1.2e+2"

Как избегать ошибок при округлении десятичных чисел

В некоторых случаях toFixed и toPrecision округляют 5 не вверх, а вниз:

var numTest = 1.005;
numTest.toFixed(2);
> 1;

Результат выше должен быть 1.01, а не 1. Если для вас важна точность, я бы порекомендовал вам решение от Jack L Moore, который в вычислениях использует экспоненциальные числа:

function round(value, decimals) {
    return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}

И результат:

round(1.005,2);
> 1.01

На MDN есть еще более надежное решение.

Усечение десятичных чисел

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

function truncated(num) {
    return Math.trunc(num * 100) / 100;
}

truncated(3.1416)
> 3.14

Если хотите добавить немного гибкости, можно воспользоваться побитовым оператором ~~:

function truncated(num, decimalPlaces) {    
    var numPowerConverter = Math.pow(10, decimalPlaces); 
    return ~~(num * numPowerConverter)/numPowerConverter;
}

Результат:

var randInt = 35.874993;
truncated(randInt,3);
> 35.874

В следующей статье я поподробнее расскажу про побитовые операции.

Округление в сторону ближайшего числа

Для округления десятичного число вверх или вниз до ближайшего целого используйте Math.round():

Math.round(4.3)
> 4

Math.round(4.5)
> 5

Обратите внимание, что «половинные значения» типа .5 округляются вверх.

Округление вниз до ближайшего целого числа

Если вам необходимо округлить число вниз, воспользуйтесь Math.floor:

Math.floor(42.23);
> 42

Math.floor(36.93);
> 36

Обратите внимание, что в данном случае округляются вниз все числа, даже отрицательные. Представьте себе небоскреб с бесконечным количеством этажей вверх и вниз (нижние этажи это отрицательные числа). Если вы в лифте находитесь между минус вторым и минус третьим этажами (значение -2.5), метод Math.floor доставит вам на -3 этаж:

Math.floor(-2.5);
> -3

Если вы не хотите, чтобы отрицательные числа тоже округлялись в меньшую сторону, воспользуйтесь Math.trunc. Данный метод поддерживается во всех современных браузерах )кроме IE/Edge):

Math.trunc(-41.43);
> -41

На MDN также есть трехстрочный полифил, который добавляют Math.trunc поддержку старых браузеров и IE/Edge.

Округление вверх до ближайшего целого числа

И наоборот, если вы хотите округлять числа вверх, используйте Math.ceil. Опять представьте бесконечный лифт: Math.ceil всегда доставит вас на ближайший верхний этаж, в независимости от знака числа:

Math.ceil(42.23);
> 43

Math.ceil(36.93);
> 37

Округление вверх и вниз до ближайшего кратного числа

Если необходимо округлить число до ближайшего кратного пяти, легче всего создать функцию, которая разделит число на 5, округлит его и умножит обратно:

function roundTo5(num) {
    return Math.round(num/5)*5;
}

Результат:

roundTo5(11);
> 10

Если необходимо округлять числа под разные кратные, можно изменить функцию и передавать в нее как аргументы оба значения, число и кратность:

function roundToMultiple(num, multiple) {
    return Math.round(num/multiple)*multiple;
}

Чтобы вызвать функцию, необходимо указать два параметра, само число и кратность:

var initialNumber = 11;
var multiple = 10;
roundToMultiple(initialNumber, multiple);
> 10;

Чтобы округлять вниз или вверх ставьте в функции ceil или floor.

Установка диапазона для числа

Бывает множество случаев, когда мы получаем число Х, и нам необходимо загнать его в определенный диапазон. К примеру, нам нужно число от 1 до 100, а получили мы 123. Тут нам пригодятся методы min (всегда возвращает наименьшее из набора чисел) и max (наибольшее число из набора). Пример с диапазоном от 1 до 100:

var lowBound = 1;
var highBound = 100;
var numInput = 123;
var clamped = Math.max(lowBound, Math.min(numInput, highBound));
console.log(clamped);
> 100;

Это можно превратить в функцию или расширение класса Number, вариант с расширением впервые предложил Daniel X. Moore:

Number.prototype.clamp = function(min, max) {
  return Math.min(Math.max(this, min), max);
};

Результат:

(numInput).clamp(lowBound, highBound);

Округление по Гауссу

Округление по Гауссу, которое также называют округлением для «банкиров», конвергентным округлением, голландским округлением и нечетным-четным округлением, это метод округления без статистического смещения; в обычном округлении числа автоматически завышаются. В округлении по Гауссу число приводится к ближайшему четному. Лучшее известное мне решение у Tim Down:

function gaussRound(num, decimalPlaces) {
    var d = decimalPlaces || 0,
    m = Math.pow(10, d),
    n = +(d ? num * m : num).toFixed(8),
    i = Math.floor(n), f = n - i,
    e = 1e-8,
    r = (f > 0.5 - e && f < 0.5 + e) ?
		((i % 2 == 0) ? i : i + 1) : Math.round(n);
    return d ? r / m : r;
}

Результат:

gaussRound(2.5)
> 2

gaussRound(3.5)
> 4

gaussRound(2.57,1)
> 2.6

Десятичные числа в CSS

JavaScript часто используют для вычисления позиции или значения трансформации HTML элементов. У вас может возникнуть вопрос, а что будет, если задать десятичное значение элементу:

#box { width: 63.667731993px; }

Плюс для нас в том, что современные браузеры понимают десятичные значения, присвоенные к блоковым элементам, в том числе проценты и пиксели.

Источник: http://thenewcode.com/

Редакция: Команда webformyself.

JavaScript&jQuery с нуля до профи

Пройдите пошаговый видеокурс по JavaScript&jQuery

Научиться

Метки:

Комментарии Вконтакте:

Комментарии Facebook:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree