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: Ти серйозно?
Гуффа

Відповіді:


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: Тоді здається, що у вас є рядок замість числа.
Гуффа

1
.toFixed () чудово працює в сучасних браузерах (я протестував Chrome, Firefox, IE11, IE8). @Bat_Programmer - уточнюйте, у яких браузерах ви вважаєте помилку.
robocat

243

Я думаю, що тут є більш простий підхід до всіх наведених тут методів і це 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)); повернути float, якщо користувач має десяткові знаки.
Стівен Ромеро

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. Перетворити число в String, а потім перетворити - це єдиний спосіб.
hiway

2
Існує помилка з цим методом: toFixed (-0,1111, 2) повертає 0,11, тобто негативний знак втрачається.
Метт

Чудово працює, за винятком того, що я в кінці додав parseFloat (результат). Варто редагувати.
Артур Барсегян

16

Завжди є кращий спосіб робити речі.

var number = 51.93999999999761;

Я хотів би отримати чотиризначну точність: 51,94

просто роби:

number.toPrecision(4);

результат буде: 51,94


2
А що робити, якщо додати 100? Вам потрібно змінити його на number.toPrecision (5)?
JohnnyBizzle

2
Так. 31.939383.toPrecision (4)> "31.94" / 131.939383.toPrecision (4)> "131.9"
ReSpawN

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 ()


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;
}

У вашому коді є помилка. Я спробував toFixed (2.01, 4) і отримав результат "2.100". Якщо я коли-небудь знайду спосіб виправити це, викладу це як відповідь на це питання.
Еліас Замарія

@ mikez302: обчислення оббивки було вимкнено одним; Ви повинні працювати зараз, але сміливо знову клопіть мене, якщо вона все-таки зламана ...
Крістоф

Дуже дивно. Коли я запускаю цю функцію з відкритою консоллю firebug у firefox 17, вона замикає весь браузер, як js потрапляє в нескінченний цикл. Навіть якщо я не console.log вихід. Якщо у мене не активовано firebug, помилка не виникає.
SublymeRick

1
Оновлення, я запустив його в chrome і отримую: Uncaught RangeError: Максимальний розмір стека викликів перевищений щодо виклику функції toFixed.
SublymeRick

@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, ви отримаєте деяку несподівано довгу десяткову частину (це пов'язано з арифметикою з плаваючою комою).

Коментар користувача на Формат номеру, щоб завжди показувати два знаки після коми, називає цю техніку масштабуванням.

Деякі згадують, що є випадки, які не крутяться, як очікувалося, і на веб- сайті http://www.jacklmoore.com/notes/rounding-in-javascript/ пропонується замість цього:

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

btw, POSITS є перспективними для майбутніх архітектур, що працюють в
Джордж Бірбіліс

-2

Якщо вас не дуже цікавить округлення, просто додайте toFixed (x), а потім вилучіть 0es і крапку, якщо потрібно. Це не швидке рішення.

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", коли значення не визначене.
Хуан Керрі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.