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

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

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

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

Ответ 1

Чтобы форматировать число с использованием нотации с фиксированной точкой, вы можете просто использовать метод 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, вам понадобится ваш собственный полиполк или использование библиотеки. Вы можете посмотреть на mosilla polyfill для этого https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round

Ответ 2

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

Ответ 3

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

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

Ответ 4

Я не знаю, почему я не могу добавить комментарий к предыдущему ответу (может быть, я безнадежно слепой, не знаю), но я придумал решение, используя ответ @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 three 0 вправо от десятичного значения. Поэтому его следует использовать безопасно.

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

Так что в значительной степени это. Используйте его хорошо;)

EDIT: добавлена ​​функциональность для "коррекции" отрицательных чисел.

Ответ 5

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

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

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

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

Ответ 6

toFixed (n) обеспечивает n длину после десятичной точки; toPrecision (х) обеспечивает общую длину 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);

Ответ 7

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

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

Ответ 8

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

DEMO ONLINE:

http://jsfiddle.net/c4Wqn/

Ответ 9

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

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

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

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

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

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 рекомендует округление до ближайшего, привязка к даже по умолчанию поведение для операций с плавающей запятой. Такие модификации оставляются в качестве упражнения для читателя:)

Ответ 10

Здесь простой

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

Ответ 11

Завершите свое десятичное значение, затем используйте 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

Ответ 12

Поместите следующий в какой-либо глобальной области:

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

и , затем попробуйте:

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

Update

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

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

Ответ 14

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

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

Ответ 15

Используя этот ответ по ссылке: fooobar.com/questions/15040/...

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

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/

Ответ 16

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>

Ответ 17

Округлить

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

Слияние fooobar.com/questions/56329/... и https://www.kirupa.com/html5/rounding_numbers_in_javascript.htm Спасибо им.

Ответ 18

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

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

Ответ 19

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

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

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

"Тип" строка "не присваивается типу" число ""

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

Для пояснения см. Пример ниже:

ПРИМЕР: У меня есть количество, которое имеет до 5 цифр в десятичных знаках, и я хотел бы сократить его до 2 десятичных знаков. Я делаю это так:

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

Ответ 20

(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

и др.

Ответ 21

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

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

Ответ 22

/*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.
*/

Ответ 23

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

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. Как и лучшие из них!

Ответ 24

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

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

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

Ответ 25

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

Ответ 26

100% работает!!! Попробуйте

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