Форматирование числа с ровно двумя десятичными знаками в JavaScript

У меня есть эта строка кода, которая округляет числа до двух десятичных знаков. Но я получаю такие цифры:10.8, 2.4 и т. д. Это не моя идея двух знаков после запятой, так как я могу улучшить следующее?

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

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

28 ответов


чтобы отформатировать число с помощью фиксированной точки, вы можете просто использовать 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


это старая тема, но по-прежнему топовые результаты 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

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

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>

Я обычно добавляю это в свою личную библиотеку, и после некоторых предложений и использования решения @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);
}

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


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

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

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


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

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

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

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

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

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

    // 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);
    

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

    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

    @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/


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

    когда компьютер хранит 1.275 как значение с плавающей запятой, он фактически не будет помнить, было ли это 1.275 или 1.27499999999999993, или даже 1.275000000000002. Эти значения должны давать разные результаты после округления до двух десятичные дроби, но они не будут, так как для компьютера они выглядят точно так же после хранения в качестве значений с плавающей запятой, и нет никакого способа восстановить потерянные данные. Любые дальнейшие расчеты будут только накапливать такую неточность.

    Итак, если точность имеет значение, вы должны избегать значений с плавающей запятой с самого начала. Простейшие варианты

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

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

    function descale(num, decimals) {
        var hasMinus = num < 0;
        var numString = Math.abs(num).toString();
        var precedingZeroes = '';
        for (var i = numString.length; i <= decimals; i++) {
            precedingZeroes += '0';
        }
        numString = precedingZeroes + numString;
        return (hasMinus ? '-' : '') 
            + numString.substr(0, numString.length-decimals) 
            + '.' 
            + numString.substr(numString.length-decimals);
    }
    
    alert(descale(127, 2));
    

    со строками вам понадобится округление, но это все еще управляемо:

    function precise_round(num, decimals) {
        var parts = num.split('.');
        var hasMinus = parts.length > 0 && parts[0].length > 0 && parts[0].charAt(0) == '-';
        var integralPart = parts.length == 0 ? '0' : (hasMinus ? parts[0].substr(1) : parts[0]);
        var decimalPart = parts.length > 1 ? parts[1] : '';
        if (decimalPart.length > decimals) {
            var roundOffNumber = decimalPart.charAt(decimals);
            decimalPart = decimalPart.substr(0, decimals);
            if ('56789'.indexOf(roundOffNumber) > -1) {
                var numbers = integralPart + decimalPart;
                var i = numbers.length;
                var trailingZeroes = '';
                var justOneAndTrailingZeroes = true;
                do {
                    i--;
                    var roundedNumber = '1234567890'.charAt(parseInt(numbers.charAt(i)));
                    if (roundedNumber === '0') {
                        trailingZeroes += '0';
                    } else {
                        numbers = numbers.substr(0, i) + roundedNumber + trailingZeroes;
                        justOneAndTrailingZeroes = false;
                        break;
                    }
                } while (i > 0);
                if (justOneAndTrailingZeroes) {
                    numbers = '1' + trailingZeroes;
                }
                integralPart = numbers.substr(0, numbers.length - decimals);
                decimalPart = numbers.substr(numbers.length - decimals);
            }
        } else {
            for (var i = decimalPart.length; i < decimals; i++) {
                decimalPart += '0';
            }
        }
        return (hasMinus ? '-' : '') + integralPart + (decimals > 0 ? '.' + decimalPart : '');
    }
    
    alert(precise_round('1.275', 2));
    alert(precise_round('1.27499999999999993', 2));
    

    обратите внимание, что это функция округляет до ближайшего,связи от нуля, а IEEE 754 рекомендует округление до ближайшего, связи с even как поведение по умолчанию для операций с плавающей запятой. Такие модификации оставляются в качестве упражнения для читателя:)


    вот простой

    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


    округлите десятичное значение, затем используйте toFixed(x) для ожидаемой цифры(цифр).

    function parseDecimalRoundAndFixed(num,dec){
      var d =  Math.pow(10,dec);
      return (Math.round(num * d) / d).toFixed(dec);
    }
    

    вызов

    parseDecimalRoundAndFixed(10.800243929, 4) => 10.80 parseDecimalRoundAndFixed(10.807243929,2) => 10.81


    поставить следующее в каких-то глобальных масштабов:

    Number.prototype.getDecimals = function ( decDigCount ) {
       return this.toFixed(decDigCount);
    }
    

    и попробуйте:

    var a = 56.23232323;
    a.getDecimals(2); // will return 56.23
    

    обновление

    отметим, что toFixed() может работать только для количества десятичных знаков между 0-20 то есть a.getDecimals(25) может генерировать ошибку javascript, поэтому для размещения Вы можете добавить дополнительную проверку, т. е.

    Number.prototype.getDecimals = function ( decDigCount ) {
       return ( decDigCount > 20 ) ? this : this.toFixed(decDigCount);
    }
    

    Number(((Math.random() * 100) + 1).toFixed(2))
    

    это вернет случайное число от 1 до 100 округленных до 2 десятичных знаков.


    Number(Math.round(1.005+'e2')+'e-2'); // 1.01
    

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


    используя этот ответ по ссылке:https://stackoverflow.com/a/21029698/454827

    Я создаю функцию для получения динамических чисел десятичных дробей:

    function toDec(num, dec)
    {
            if(typeof dec=='undefined' || dec<0)
                    dec = 2;
    
            var tmp = dec + 1;
            for(var i=1; i<=tmp; i++)
                    num = num * 10;
    
            num = num / 10;
            num = Math.round(num);
            for(var i=1; i<=dec; i++)
                    num = num / 10;
    
            num = num.toFixed(dec);
    
            return num;
    }
    

    вот рабочий пример:https://jsfiddle.net/wpxLduLc/


    parse = function (data) {
           data = Math.round(data*Math.pow(10,2))/Math.pow(10,2);
           if (data != null) {
                var lastone = data.toString().split('').pop();
                if (lastone != '.') {
                     data = parseFloat(data);
                }
           }
           return data;
      };
    
    $('#result').html(parse(200)); // output 200
    $('#result1').html(parse(200.1)); // output 200.1
    $('#result2').html(parse(200.10)); // output 200.1
    $('#result3').html(parse(200.109)); // output 200.11
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
    <div id="result"></div>
    <div id="result1"></div>
    <div id="result2"></div>
    <div id="result3"></div>

    округлить

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

    круглый

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

    округление до ближайшего

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

    слились https://stackoverflow.com/a/7641824/1889449 и https://www.kirupa.com/html5/rounding_numbers_in_javascript.htm Спасибо их.


    С этими примерами вы все равно получите ошибку при попытке округлить число 1.005 решение заключается в использовании библиотеки, такой как Math.js или эта функция:

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

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

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

    1) Во-первых, вы применяете .toFixed(2) на число, которое вы хотите округлить десятичные знаки. Обратите внимание, что это преобразует значение в строку из number. Поэтому, если вы используете 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);

    Я получил некоторые идеи из этого сообщения несколько месяцев назад, но ни один из ответов здесь, ни ответы из других сообщений/блогов не могли обрабатывать все сценарии (например, отрицательные числа и некоторые "счастливые числа" наш тестер нашел). В конце концов, наш тестер не нашел никаких проблем с этим методом ниже. Вставка фрагмента моего кода:

    fixPrecision: function (value) {
        var me = this,
            nan = isNaN(value),
            precision = me.decimalPrecision;
    
        if (nan || !value) {
            return nan ? '' : value;
        } else if (!me.allowDecimals || precision <= 0) {
            precision = 0;
        }
    
        //[1]
        //return parseFloat(Ext.Number.toFixed(parseFloat(value), precision));
        precision = precision || 0;
        var negMultiplier = value < 0 ? -1 : 1;
    
        //[2]
        var numWithExp = parseFloat(value + "e" + precision);
        var roundedNum = parseFloat(Math.round(Math.abs(numWithExp)) + 'e-' + precision) * negMultiplier;
        return parseFloat(roundedNum.toFixed(precision));
    },
    

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

    9.995 * 100 = 999.4999999999999
    Whereas 9.995e2 = 999.5
    This discrepancy causes Math.round(9.995 * 100) = 999 instead of 1000.
    Use e notation instead of multiplying /dividing by Math.Pow(10,precision).
    

    я исправляю проблему модификатора. поддержка только 2 десятичных знаков.

    $(function(){
      //input number only.
      convertNumberFloatZero(22); // output : 22.00
      convertNumberFloatZero(22.5); // output : 22.50
      convertNumberFloatZero(22.55); // output : 22.55
      convertNumberFloatZero(22.556); // output : 22.56
      convertNumberFloatZero(22.555); // output : 22.55
      convertNumberFloatZero(22.5541); // output : 22.54
      convertNumberFloatZero(22222.5541); // output : 22,222.54
    
      function convertNumberFloatZero(number){
    	if(!$.isNumeric(number)){
    		return 'NaN';
    	}
    	var numberFloat = number.toFixed(3);
    	var splitNumber = numberFloat.split(".");
    	var cNumberFloat = number.toFixed(2);
    	var cNsplitNumber = cNumberFloat.split(".");
    	var lastChar = splitNumber[1].substr(splitNumber[1].length - 1);
    	if(lastChar > 0 && lastChar < 5){
    		cNsplitNumber[1]--;
    	}
    	return Number(splitNumber[0]).toLocaleString('en').concat('.').concat(cNsplitNumber[1]);
      };
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

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

    что должно получиться: 10.20

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

    что должно получиться: 0.05

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

    что должно получиться: 4.04

    etc.


    /*Due to all told stuff. You may do 2 things for different purposes:
    When showing/printing stuff use this in your alert/innerHtml= contents:
    YourRebelNumber.toFixed(2)*/
    
    var aNumber=9242.16;
    var YourRebelNumber=aNumber-9000;
    alert(YourRebelNumber);
    alert(YourRebelNumber.toFixed(2));
    
    /*and when comparing use:
    Number(YourRebelNumber.toFixed(2))*/
    
    if(YourRebelNumber==242.16)alert("Not Rounded");
    if(Number(YourRebelNumber.toFixed(2))==242.16)alert("Rounded");
    
    /*Number will behave as you want in that moment. After that, it'll return to its defiance.
    */

    Это очень просто и работает так же хорошо, как и любой другой:

    function parseNumber(val, decimalPlaces) {
        if (decimalPlaces == null) decimalPlaces = 0
        var ret = Number(val).toFixed(decimalPlaces)
        return Number(ret)
    }
    

    поскольку toFixed () может вызываться только на числах и, к сожалению, возвращает строку, это делает все синтаксический анализ для вас в обоих направлениях. Вы можете передать строку или число, и вы получите количество каждый раз! Вызов parseNumber(1.49) даст вам 1, а parseNumber (1.49,2) даст вам 1.50. Как и лучшие из них!


    вы также можете использовать .toPrecision() метод и некоторый пользовательский код, и всегда округляйте до n-й десятичной цифры независимо от длины части int.

    function glbfrmt (number, decimals, seperator) {
        return typeof number !== 'number' ? number : number.toPrecision( number.toString().split(seperator)[0].length + decimals);
    }
    

    вы также можете сделать его плагином для лучшего использования.


    /**
     * MidpointRounding away from zero ('arithmetic' rounding)
     * Uses a half-epsilon for correction. (This offsets IEEE-754
     * half-to-even rounding that was applied at the edge cases).
     */
    
    function RoundCorrect(num, precision = 2) {
    	// half epsilon to correct edge cases.
    	var c = 0.5 * Number.EPSILON * num;
    //	var p = Math.pow(10, precision); //slow
    	var p = 1; while (precision--> 0) p *= 10;
    	if (num < 0)
    		p *= -1;
    	return Math.round((num + c) * p) / p;
    }
    
    // testing some +ve edge cases
    console.log(RoundCorrect(1.005, 2));  // 1.01 correct
    console.log(RoundCorrect(2.175, 2));  // 2.18 correct
    console.log(RoundCorrect(5.015, 2));  // 5.02 correct
    
    // testing some -ve edge cases
    console.log(RoundCorrect(-1.005, 2));  // -1.01 correct
    console.log(RoundCorrect(-2.175, 2));  // -2.18 correct
    console.log(RoundCorrect(-5.015, 2));  // -5.02 correct

    как это просто.

    var rounded_value=Math.round(value * 100) / 100;
    

    100% рабочий!!! Попробуйте!--2-->

    <html>
         <head>
          <script>
          function replacePonto(){
            var input = document.getElementById('qtd');
            var ponto = input.value.split('.').length;
            var slash = input.value.split('-').length;
            if (ponto > 2)
                    input.value=input.value.substr(0,(input.value.length)-1);
    
            if(slash > 2)
                    input.value=input.value.substr(0,(input.value.length)-1);
    
            input.value=input.value.replace(/[^0-9.-]/,'');
    
            if (ponto ==2)
    	input.value=input.value.substr(0,(input.value.indexOf('.')+3));
    
    if(input.value == '.')
    	input.value = "";
                  }
          </script>
          </head>
          <body>
             <input type="text" id="qtd" maxlength="10" style="width:140px" onkeyup="return replacePonto()">
          </body>
        </html>