Форматирование числа с точностью до двух десятичных знаков в 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 ]

2 голосов
/ 07 ноября 2014

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

2 голосов
/ 18 февраля 2018

/**
 * 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
2 голосов
/ 07 августа 2013

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

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

1 голос
/ 20 ноября 2015
Number(((Math.random() * 100) + 1).toFixed(2))

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

1 голос
/ 25 сентября 2018

Простой, как этот.

var rounded_value=Math.round(value * 100) / 100;
1 голос
/ 13 марта 2015
Number(Math.round(1.005+'e2')+'e-2'); // 1.01

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

1 голос
/ 16 июля 2014

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

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);
}
1 голос
/ 24 сентября 2018

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

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).
1 голос
/ 10 февраля 2018

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

function round(value: number, decimals: number) {
    return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
}
1 голос
/ 28 января 2018

Округление вниз

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 Спасибо их.

...