Javascript: форматирование округленного числа до N десятичных знаков

104

в JavaScript типичный способ округления числа до N десятичных знаков выглядит примерно так:

function roundNumber(num, dec) {
  return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
}

Однако этот подход будет округляться максимум до N десятичных знаков, в то время как я хочу всегда округлять до N десятичных знаков. Например, «2,0» будет округлено до «2».

Любые идеи?

Ходзю
источник
9
обычно вы можете использовать toFixed()( developer.mozilla.org/En/Core_JavaScript_1.5_Reference/… ), но в IE есть ошибки: stackoverflow.com/questions/661562/… ; вам придется написать свою собственную версию ...
Кристоф
1
@hoju - возможно, измените принятый ответ - ответ Дэвида верен для IE8 +, в то время как принятый ответ имеет серьезные ошибки во всех браузерах.
robocat
@robocat: Ты серьезно?
Guffa

Ответы:

25

Это не проблема округления, это проблема отображения. Число не содержит информации о значащих цифрах; значение 2 совпадает с 2.0000000000000. Это когда вы превращаете округленное значение в строку, которая отображает определенное количество цифр.

Вы можете просто добавить нули после числа, например:

var s = number.toString();
if (s.indexOf('.') == -1) s += '.';
while (s.length < s.indexOf('.') + 4) s += '0';

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

Гуффа
источник
3
toFixed не работает .. например, десятичное: 1.02449999998, если вы делаете dec.toFixed (4) => 1.0244. Вместо этого должно было быть 1.0245.
Bat_Programmer
2
@deepeshk Но в чем будет проблема с добавлением toFixed()десятичных знаков в конце после округления?
pauloya
10
@deepeshk в каком браузере? Просто попробовал в Chrome 17 и 1.02449999998.toFixed(4)правильно возвращается 1.0245.
Мэтт Болл,
3
@MarkTomlin: Значит, вместо числа у вас строка.
Guffa
1
.toFixed () прекрасно работает в современных браузерах (я тестировал Chrome, Firefox, IE11, IE8). @Bat_Programmer - поясните, в каких браузерах, по вашему мнению, есть эта ошибка.
robocat
244

Я думаю, что есть более простой подход ко всему приведенному здесь, и этот метод Number.toFixed()уже реализован в JavaScript.

просто напишите:

var myNumber = 2;

myNumber.toFixed(2); //returns "2.00"
myNumber.toFixed(1); //returns "2.0"

и т.д...

Дэвид
источник
Где упоминается ходзю? Я просмотрел другие ответы, и я не нашел никого, кто сообщал бы, что функция toFixed работает с ошибками. Спасибо
Дэвид
@David: Это, например, упомянуто в комментарии к ответу.
Guffa
13
Внимание: toFixed()возвращает строку.
Джордан Арсено
2
@JordanArseno это можно исправить с помощью parseInt (myNumber.toFixed (intVar)); чтобы вернуть целочисленное значение, или parseFloat (myNumber.toFixed (floatVar)); чтобы вернуть число с плавающей запятой, если у пользователя есть десятичные знаки.
Стивен Ромеро
50

Я нашел путь. Это код Кристофа с исправлением:

function toFixed(value, precision) {
    var precision = precision || 0,
        power = Math.pow(10, precision),
        absValue = Math.abs(Math.round(value * power)),
        result = (value < 0 ? '-' : '') + String(Math.floor(absValue / power));

    if (precision > 0) {
        var fraction = String(absValue % power),
            padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');
        result += '.' + padding + fraction;
    }
    return result;
}

Прочтите подробности повторения символа с помощью конструктора массива здесь, если вам интересно, почему я добавил «+ 1».

Элиас Замария
источник
Передача значения 708,3333333333333 с точностью 2 или 3 приводит к возвращаемому значению 708,00 для меня. Мне это нужно для двух знаков после запятой, в Chrome и IE 9. toFixed (2) удовлетворил мои потребности.
Алан
это не обычный способ, например, toFixed (16.775, 2) вернет 16.77. Преобразовать число в строку, а затем преобразовать - единственный способ.
hiway, 04
2
В этом методе есть ошибка: toFixed (-0.1111, 2) возвращает 0.11, т.е. отрицательный знак теряется.
Мэтт
Отлично работает, за исключением того, что я добавил в конце parseFloat (результат). Стоит отредактировать.
Артур Барсегян
16

Всегда есть способ сделать что-то лучше.

var number = 51.93999999999761;

Я хочу получить четырехзначную точность: 51,94

просто сделать:

number.toPrecision(4);

результат будет: 51.94

de.la.ru
источник
2
А если прибавить 100? Вам нужно изменить его на number.toPrecision (5)?
JohnnyBizzle
2
Да. 31.939383.toPrecision (4)> "31.94" / 131.939383.toPrecision (4)> "131.9"
ReSpawN 03
6

PHP-подобный метод округления

Приведенный ниже код можно использовать для добавления вашей собственной версии Math.round в ваше собственное пространство имен, которое принимает параметр точности. В отличие от десятичного округления в приведенном выше примере, здесь не выполняется преобразование в строки и из строк, а параметр точности работает так же, как в PHP и Excel, при этом положительное значение 1 округляется до 1 десятичного знака, а -1 - до десятков.

var myNamespace = {};
myNamespace.round = function(number, precision) {
    var factor = Math.pow(10, precision);
    var tempNumber = number * factor;
    var roundedTempNumber = Math.round(tempNumber);
    return roundedTempNumber / factor;
};

myNamespace.round(1234.5678, 1); // 1234.6
myNamespace.round(1234.5678, -1); // 1230

из справочника разработчика Mozilla для Math.round ()

JohnnyBizzle
источник
2

Надеюсь, рабочий код (много не тестировал):

function toFixed(value, precision) {
    var precision = precision || 0,
        neg = value < 0,
        power = Math.pow(10, precision),
        value = Math.round(value * power),
        integral = String((neg ? Math.ceil : Math.floor)(value / power)),
        fraction = String((neg ? -value : value) % power),
        padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');

    return precision ? integral + '.' +  padding + fraction : integral;
}
Кристоф
источник
В вашем коде есть ошибка. Я попробовал исправить (2.01, 4) и получил результат «2.100». Если я когда-нибудь найду способ исправить это, я отправлю его в качестве ответа на этот вопрос.
Элиас Замария
@ mikez302: вычисление заполнения было отключено на единицу; должно работать, но не стесняйтесь жуку меня снова , если это все-таки сломано ...
Christoph
Очень странно. Когда я запускаю эту функцию с открытой консолью firebug в firefox 17, он замораживает весь браузер, как будто js попадает в бесконечный цикл. Даже если я не использую console.log вывод. Если у меня не активирован firebug, ошибка не возникает.
SublymeRick 07
1
Обновите, я запустил его в хроме и получил: Uncaught RangeError: Превышен максимальный размер стека вызовов в отношении вызова функции toFixed.
SublymeRick 07
@SublymeRick: Понятия не имею, почему это происходит; выстрел в темноте: попробуйте переименовать функцию ...
Кристоф
2

Я думаю, что функция ниже может помочь

function roundOff(value,round) {
   return (parseInt(value * (10 ** (round + 1))) - parseInt(value * (10 ** round)) * 10) > 4 ? (((parseFloat(parseInt((value + parseFloat(1 / (10 ** round))) * (10 ** round))))) / (10 ** round)) : (parseFloat(parseInt(value * (10 ** round))) / ( 10 ** round));
}

использование: roundOff(600.23458,2);вернется600.23

КРИШНА ТЕЖА
источник
2

Это работает для округления до N цифр (если вы просто хотите усечь до N цифр, удалите вызов Math.round и используйте Math.trunc):

function roundN(value, digits) {
   var tenToN = 10 ** digits;
   return /*Math.trunc*/(Math.round(value * tenToN)) / tenToN;
}

Раньше приходилось прибегать к такой логике на Java, когда я создавал компоненты E-Slate для обработки данных . Это потому, что я обнаружил, что добавляя 0,1 много раз к 0, вы получите неожиданно длинную десятичную часть (это связано с арифметикой с плавающей запятой).

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

Некоторые упоминают, что есть случаи, которые не округляются, как ожидалось, и на http://www.jacklmoore.com/notes/rounding-in-javascript/ предлагается вместо этого:

function round(value, decimals) {
  return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
}
Джордж Бирбилис
источник
Между прочим, POSITS многообещающи для будущих ч / б архитектур: nextplatform.com/2019/07/08/…
Джордж Бирбилис 08
-2

Если вас не волнует округление, просто добавьте toFixed (x), а затем удалите конечные 0 и точку, если это необходимо. Это не быстрое решение.

function format(value, decimals) {
    if (value) {
        value = value.toFixed(decimals);            
    } else {
        value = "0";
    }
    if (value.indexOf(".") < 0) { value += "."; }
    var dotIdx = value.indexOf(".");
    while (value.length - dotIdx <= decimals) { value += "0"; } // add 0's

    return value;
}
Хуан Керри
источник
Я попробовал format(1.2, 5)и получил 1.2, хотя ожидал 1.20000.
Элиас Замария
Извините, @EliasZamaria, сначала не понял. Я отредактировал сообщение. Просто обратите внимание, что он вернет «0.0000», если значение не определено.
Хуан Керри,