Форматирование числа с точностью до двух десятичных знаков в JavaScript - PullRequest
540 голосов
/ 13 ноября 2009

У меня есть эта строка кода, которая округляет мои числа до двух десятичных знаков. Но я получаю такие числа: 10,8, 2,4 и т. Д. Это не мое представление о двух десятичных знаках, так как я могу улучшить следующее?

Math.round(price*Math.pow(10,2))/Math.pow(10,2);

Мне нужны числа вроде 10.80, 2.40 и т. Д. Использование jQuery хорошо для меня.

Ответы [ 29 ]

938 голосов
/ 13 ноября 2009

Чтобы отформатировать число с использованием записи с фиксированной запятой, вы можете просто использовать метод toFixed :

(10.8).toFixed(2); // "10.80"

var num = 2.4;
alert(num.toFixed(2)); // "2.40"

Обратите внимание, что toFixed() возвращает строку.

ВАЖНО : обратите внимание, что toFixed фактически не округляется, 90% времени, он возвращает округленное значение, но во многих случаях он фактически не работает. Попробуйте это в своей консоли:

2.005.toFixed(2)

Вы получите неправильный ответ

Нет естественного способа получить десятичное округление в javascript, вам понадобится ваш собственный polyfill или использовать библиотеку. Вы можете посмотреть на polyfill Mozilla для этого https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round

91 голосов
/ 24 января 2014

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

function round(value, exp) {
  if (typeof exp === 'undefined' || +exp === 0)
    return Math.round(value);

  value = +value;
  exp = +exp;

  if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
    return NaN;

  // Shift
  value = value.toString().split('e');
  value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));

  // Shift back
  value = value.toString().split('e');
  return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}

Как мы видим, мы не получаем следующие проблемы:

round(1.275, 2);   // Returns 1.28
round(1.27499, 2); // Returns 1.27

Этот тип также предоставляет некоторые интересные вещи:

round(1234.5678, -2);   // Returns 1200
round(1.2345678e+2, 2); // Returns 123.46
round("123.45");        // Returns 123

Теперь, чтобы ответить на вопрос ОП, нужно набрать:

round(10.8034, 2).toFixed(2); // Returns "10.80"
round(10.8, 2).toFixed(2);    // Returns "10.80"

Или, для более краткой, менее обобщенной функции:

function round2Fixed(value) {
  value = +value;

  if (isNaN(value))
    return NaN;

  // Shift
  value = value.toString().split('e');
  value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + 2) : 2)));

  // Shift back
  value = value.toString().split('e');
  return (+(value[0] + 'e' + (value[1] ? (+value[1] - 2) : -2))).toFixed(2);
}

Вы можете позвонить по этому номеру:

round2Fixed(10.8034); // Returns "10.80"
round2Fixed(10.8);    // Returns "10.80"

Различные примеры и тесты (благодаря @ t-j-crowder !):

function round(value, exp) {
  if (typeof exp === 'undefined' || +exp === 0)
    return Math.round(value);

  value = +value;
  exp = +exp;

  if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
    return NaN;

  // Shift
  value = value.toString().split('e');
  value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));

  // Shift back
  value = value.toString().split('e');
  return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}
function naive(value, exp) {
  if (!exp) {
    return Math.round(value);
  }
  var pow = Math.pow(10, exp);
  return Math.round(value * pow) / pow;
}
function test(val, places) {
  subtest(val, places);
  val = typeof val === "string" ? "-" + val : -val;
  subtest(val, places);
}
function subtest(val, places) {
  var placesOrZero = places || 0;
  var naiveResult = naive(val, places);
  var roundResult = round(val, places);
  if (placesOrZero >= 0) {
    naiveResult = naiveResult.toFixed(placesOrZero);
    roundResult = roundResult.toFixed(placesOrZero);
  } else {
    naiveResult = naiveResult.toString();
    roundResult = roundResult.toString();
  }
  $("<tr>")
    .append($("<td>").text(JSON.stringify(val)))
    .append($("<td>").text(placesOrZero))
    .append($("<td>").text(naiveResult))
    .append($("<td>").text(roundResult))
    .appendTo("#results");
}
test(0.565, 2);
test(0.575, 2);
test(0.585, 2);
test(1.275, 2);
test(1.27499, 2);
test(1234.5678, -2);
test(1.2345678e+2, 2);
test("123.45");
test(10.8034, 2);
test(10.8, 2);
test(1.005, 2);
test(1.0005, 2);
table {
  border-collapse: collapse;
}
table, td, th {
  border: 1px solid #ddd;
}
td, th {
  padding: 4px;
}
th {
  font-weight: normal;
  font-family: sans-serif;
}
td {
  font-family: monospace;
}
<table>
  <thead>
    <tr>
      <th>Input</th>
      <th>Places</th>
      <th>Naive</th>
      <th>Thorough</th>
    </tr>
  </thead>
  <tbody id="results">
  </tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
41 голосов
/ 12 февраля 2013

Я обычно добавляю это в свою личную библиотеку, и после некоторых предложений и использования решения @TIMINeutron, а затем, делая его адаптируемым для десятичной длины, этот вариант подходит лучше всего:

function precise_round(num, decimals) {
   var t = Math.pow(10, decimals);   
   return (Math.round((num * t) + (decimals>0?1:0)*(Math.sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals);
}

будет работать для зарегистрированных исключений.

16 голосов
/ 01 мая 2013

Я не знаю, почему я не могу добавить комментарий к предыдущему ответу (возможно, я безнадежно слеп, не знаю), но я нашел решение, используя ответ @ Miguel:

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

И два комментария (от @bighostkim и @Imre):

  • Проблема с precise_round(1.275,2) не возвращается 1.28
  • Проблема с precise_round(6,2), не возвращающим 6,00 (как он хотел).

Мое окончательное решение заключается в следующем:

function precise_round(num,decimals) {
    var sign = num >= 0 ? 1 : -1;
    return (Math.round((num*Math.pow(10,decimals)) + (sign*0.001)) / Math.pow(10,decimals)).toFixed(decimals);
}

Как видите, мне пришлось добавить немного «исправления» (это не то, что есть, но поскольку Math.round с потерями - вы можете проверить это на jsfiddle.net - это единственный способ, которым я знал, как починить это). Он добавляет 0,001 к уже дополненному номеру, поэтому он добавляет 1 три 0 с справа от десятичного значения. Так что это должно быть безопасно для использования.

После этого я добавил .toFixed(decimal), чтобы всегда выводить число в правильном формате (с правильным количеством десятичных знаков).

Вот и все. Используйте это хорошо;)

РЕДАКТИРОВАТЬ: добавлена ​​функциональность для «коррекции» отрицательных чисел.

14 голосов
/ 09 января 2014

Один способ быть на 100% уверенным, что вы получите число с двумя десятичными знаками:

(Math.round(num*100)/100).toFixed(2)

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

(Math.round((num * 1000)/10)/100).toFixed(2)
12 голосов
/ 17 апреля 2012

toFixed (n) предоставляет n длины после десятичной точки; toPrecision (х) обеспечивает общую длину х.

Используйте этот метод ниже

// Example: toPrecision(4) when the number has 7 digits (3 before, 4 after)
    // It will round to the tenths place
    num = 500.2349;
    result = num.toPrecision(4); // result will equal 500.2

И если вы хотите, чтобы номер был фиксированным, используйте

result = num.toFixed(2);
5 голосов
/ 29 апреля 2013

Я не нашел точного решения этой проблемы, поэтому создал свое собственное:

function inprecise_round(value, decPlaces) {
  return Math.round(value*Math.pow(10,decPlaces))/Math.pow(10,decPlaces);
}

function precise_round(value, decPlaces){
    var val = value * Math.pow(10, decPlaces);
    var fraction = (Math.round((val-parseInt(val))*10)/10);

    //this line is for consistency with .NET Decimal.Round behavior
    // -342.055 => -342.06
    if(fraction == -0.5) fraction = -0.6;

    val = Math.round(parseInt(val) + fraction) / Math.pow(10, decPlaces);
    return val;
}

Примеры:

function inprecise_round(value, decPlaces) {
  return Math.round(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}

function precise_round(value, decPlaces) {
  var val = value * Math.pow(10, decPlaces);
  var fraction = (Math.round((val - parseInt(val)) * 10) / 10);

  //this line is for consistency with .NET Decimal.Round behavior
  // -342.055 => -342.06
  if (fraction == -0.5) fraction = -0.6;

  val = Math.round(parseInt(val) + fraction) / Math.pow(10, decPlaces);
  return val;
}

// This may produce different results depending on the browser environment
console.log("342.055.toFixed(2)         :", 342.055.toFixed(2)); // 342.06 on Chrome & IE10

console.log("inprecise_round(342.055, 2):", inprecise_round(342.055, 2)); // 342.05
console.log("precise_round(342.055, 2)  :", precise_round(342.055, 2));   // 342.06
console.log("precise_round(-342.055, 2) :", precise_round(-342.055, 2));  // -342.06

console.log("inprecise_round(0.565, 2)  :", inprecise_round(0.565, 2));   // 0.56
console.log("precise_round(0.565, 2)    :", precise_round(0.565, 2));     // 0.57
3 голосов
/ 27 ноября 2012

@ heridev и я создали небольшую функцию в jQuery.

Вы можете попробовать следующее:

HTML

<input type="text" name="one" class="two-digits"><br>
<input type="text" name="two" class="two-digits">​

JQuery

// apply the two-digits behaviour to elements with 'two-digits' as their class
$( function() {
    $('.two-digits').keyup(function(){
        if($(this).val().indexOf('.')!=-1){         
            if($(this).val().split(".")[1].length > 2){                
                if( isNaN( parseFloat( this.value ) ) ) return;
                this.value = parseFloat(this.value).toFixed(2);
            }  
         }            
         return this; //for chaining
    });
});

ДЕМО ОНЛАЙН:

http://jsfiddle.net/c4Wqn/

3 голосов
/ 02 января 2014

Вот простой

function roundFloat(num,dec){
    var d = 1;
    for (var i=0; i<dec; i++){
        d += "0";
    }
    return Math.round(num * d) / d;
}

Используйте как alert(roundFloat(1.79209243929,4));

Jsfiddle

2 голосов
/ 25 апреля 2018

Вот мое 1-строчное решение: Number((yourNumericValueHere).toFixed(2));

Вот что происходит:

1) Сначала вы применяете .toFixed(2) к числу, которому хотите округлить десятичные разряды. Обратите внимание, что это преобразует значение в строку из числа. Поэтому, если вы используете Typescript, он выдаст ошибку, подобную этой:

"Тип 'string' не может быть назначен типу 'number'"

2) Чтобы вернуть числовое значение или преобразовать строку в числовое значение, просто примените функцию Number() к так называемому «строковому» значению.

Для пояснения посмотрите на пример ниже:

Пример: У меня есть количество до 5 знаков после запятой, и я хотел бы сократить его до 2 знаков после запятой. Я делаю это так:

var price = 0.26453;
var priceRounded = Number((price).toFixed(2));
console.log('Original Price: ' + price);
console.log('Price Rounded: ' + priceRounded);
...