javascript - 제거 - 자바 math.round 소수점 2자리




소수점 이하 2 자리로 반올림(필요한 경우에만) (20)

나는 소수점 이하 2 자리를 반올림하고 싶다.

입력:

10
1.7777777
9.1

산출:

10
1.78
9.1

JavaScript 어떻게 할 수 있습니까?


2017 년
네이티브 코드 .toFixed()

number = 1.2345;
number.toFixed(2) // "1.23"

당신이 엄격해야하고 필요한 경우에만 숫자를 추가해야 할 경우 replace 를 사용할 수 있습니다

number = 1; // "1"
number.toFixed(5).replace(/\.?0*$/g,'');

MarkG의 대답이 올바른 것입니다. 여기에는 소수점 이하 자리수에 대한 일반적인 확장이 있습니다.

Number.prototype.round = function(places) {
  return +(Math.round(this + "e+" + places)  + "e-" + places);
}

용법:

var n = 1.7777;    
n.round(2); // 1.78

단위 테스트 :

it.only('should round floats to 2 places', function() {

  var cases = [
    { n: 10,      e: 10,    p:2 },
    { n: 1.7777,  e: 1.78,  p:2 },
    { n: 1.005,   e: 1.01,  p:2 },
    { n: 1.005,   e: 1,     p:0 },
    { n: 1.77777, e: 1.8,   p:1 }
  ]

  cases.forEach(function(testCase) {
    var r = testCase.n.round(testCase.p);
    assert.equal(r, testCase.e, 'didn\'t get right number');
  });
})

나에게 MDN 는 정답을주지 않았다.나는 toFixed 가 더 잘 작동 toFixed 것을 발견했다 . 다음은이 두 가지 예입니다.

console.log(Math.round(43000 / 80000) * 100); // wrong answer

console.log(((43000 / 80000) * 100).toFixed(2)); // correct answer


다음은이를 수행하는 간단한 방법입니다.

Math.round(value * 100) / 100

당신은 앞서 가서 당신을 위해 그것을 할 별도의 기능을 만들 수 있습니다 :

function roundToTwo(value) {
    return(Math.round(value * 100) / 100);
}

그런 다음 값을 전달하기 만하면됩니다.

두 번째 매개 변수를 추가하여 임의의 소수 자릿수로 반올림되도록 향상시킬 수 있습니다.

function myRound(value, places) {
    var multiplier = Math.pow(10, places);

    return (Math.round(value * multiplier) / multiplier);
}

당신이 사용할 수있는

function roundToTwo(num) {    
    return +(Math.round(num + "e+2")  + "e-2");
}

나는 MDN 에서 이것을 발견했다. 그들의 방법은 mentioned 1.005의 문제를 피합니다.

roundToTwo(1.005)
1.01
roundToTwo(10)
10
roundToTwo(1.7777777)
1.78
roundToTwo(9.1)
9.1
roundToTwo(1234.5678)
1234.57


이 질문은 복잡합니다.

float를 인수로 취해 소수점 두 자리까지 반올림 한 값을 반환하는 함수, roundTo2DP(num) 가 있다고 가정합니다. 이 표현들 각각은 무엇을 평가해야합니까?

  • roundTo2DP(0.014999999999999999)
  • roundTo2DP(0.0150000000000000001)
  • roundTo2DP(0.015)

'명백한'해답은 첫 번째 예제가 0.01로 반올림되어야한다는 것입니다 (0.02보다 0.01에 가깝기 때문에). 다른 두 값은 0.02로 반올림해야합니다 (0.0150000000000000001은 0.01보다 0.02에 더 가깝고 0.015는 그들과 같은 숫자가 반올림되는 수학적 관습이있다).

여러분이 짐작할 수있는 catch는 전달 된 세 개의 숫자가 모두 같기 때문에 roundTo2DP 구현하여 명백한 답을 줄 수 없다는 것 입니다. IEEE 754 이진 부동 소수점 숫자 (자바 스크립트에서 사용되는 종류)는 대부분의 정수가 아닌 숫자를 정확하게 나타낼 수 없으므로 위의 세 숫자 리터럴은 근처의 유효한 부동 소수점 숫자로 반올림됩니다. 이 숫자는 발생하는 대로 정확하게 나타납니다.

0.01499999999999999944488848768742172978818416595458984375

0.02보다 0.01에 가깝다.

브라우저 콘솔, 노드 셸 또는 다른 JavaScript 인터프리터에서 세 숫자가 모두 동일한 것을 볼 수 있습니다. 그냥 비교해보십시오.

> 0.014999999999999999 === 0.0150000000000000001
true

그래서 m = 0.0150000000000000001 , 끝나는 m정확한 값은 0.02 보다 0.01 가까워집니다. 그리고 m 을 String으로 변환하면 ...

> var m = 0.0150000000000000001;
> console.log(String(m));
0.015
> var m = 0.014999999999999999;
> console.log(String(m));
0.015

... 나는 0.015를 얻었으며, 이것은 0.02로 반올림해야하며, 이전에 56 진수로 된 숫자는 이전에이 모든 숫자가 정확히 같다고 말한 것이 아닙니다 . 그럼 어둠의 마법은 무엇입니까?

해답은 ECMAScript 사양의 7.1.12.1 : Number 형식에 적용된 ToString 에서 찾을 수 있습니다. 여기에서 일부 Number m 을 String으로 변환하는 규칙이 있습니다. 핵심 부분은 점 5이며, 정수 s 가 생성되며이 자리수는 m 의 문자열 표현에 사용됩니다.

n , ksk ≥ 1, 10 k -1s <10 k , s × 10 n - k 수 값이 m , k 가 가능한 한 작은 정수라고하자. k는 10 진수 표현의 자릿수이며, s 는 10으로 나눌 수없고, s의 최하위 자릿수는 반드시 이러한 기준에 의해 고유하게 결정되지는 않습니다.

핵심 부분은 " k 는 가능한 한 작다"는 요구 사항입니다. 요구 사항은 Number m 주어지면 Number(String(m)) === m 이라는 요구 사항을 만족하면서 String(m) 의 값이 가능한 최소 자릿수 를 가져야한다는 요구 사항입니다. 0.015 === 0.0150000000000000001 이라는 것을 이미 알고 있으므로 String(0.0150000000000000001) === '0.015' 가 true 여야하는 이유는 분명합니다.

물론,이 논의 중 어느 것도 roundTo2DP(m) 반환 해야하는 것에 직접적으로 응답하지 않았습니다. m 의 정확한 값이 0.014999999999999944488848768742172978818416595458984375이고 문자열 표현이 '0.015'이면 수학적으로, 실제적으로, 철학적으로 또는 그 밖의 소수점 이하 두 자리로 반올림 할 때 정답은 무엇입니까?

이것에 대한 정답은 하나도 없습니다. 사용 사례에 따라 다릅니다. 다음과 같은 경우 문자열 표현을 존중하고 위쪽으로 반올림합니다.

  • 표현되는 값은 본질적으로 별개입니다 (예 : dinars와 같은 소수점 이하 세 자리 통화의 통화 금액). 이 경우 0.015와 같은 Number의 실제 0.015이며 이진 부동 소수점에서 가져 오는 0.0149999999 ... 표현은 반올림 오류입니다. (물론 많은 사람들이 이러한 값을 처리하기 위해 10 진수 라이브러리를 사용해야하며 처음에는 이진 부동 소수점 숫자로 나타내지 말아야한다고 주장합니다.)
  • 값은 사용자가 입력했습니다. 이 경우에도 정확한 십진수는 가장 가까운 이진 부동 소수점 표현보다 '참'입니다.

다른 한편, 이진 부동 소수점 값을 존중하고 값이 본질적으로 연속적인 스케일 (예 : 센서에서 읽은 값) 인 경우 아래쪽으로 반올림합니다.

이 두 가지 접근 방식에는 서로 다른 코드가 필요합니다. Number의 String 표현을 존중하기 위해 우리는 꽤 합리적으로 미묘한 코드를 사용하여 문자열 표현에 직접 작용하는 자체 반올림을 구현할 수 있습니다. 숫자를 돌리는 법을 배웠습니다. 다음은 소수점 뒤에 후행 0을 제거하여 "필요한 경우에만"소수점 이하 2 자리까지 표현하는 OP의 요구 사항을 나타내는 예제입니다. 물론 정확한 요구에 맞게 조정할 필요가 있습니다.

/**
 * Converts num to a decimal string (if it isn't one already) and then rounds it
 * to at most dp decimal places.
 *
 * For explanation of why you'd want to perform rounding operations on a String
 * rather than a Number, see http://.com/a/38676273/1709587
 *
 * @param {(number|string)} num
 * @param {number} dp
 * @return {string}
 */
function roundStringNumberWithoutTrailingZeroes (num, dp) {
    if (arguments.length != 2) throw new Error("2 arguments required");

    num = String(num);
    if (num.indexOf('e+') != -1) {
        // Can't round numbers this large because their string representation
        // contains an exponent, like 9.99e+37
        throw new Error("num too large");
    }
    if (num.indexOf('.') == -1) {
        // Nothing to do
        return num;
    }

    var parts = num.split('.'),
        beforePoint = parts[0],
        afterPoint = parts[1],
        shouldRoundUp = afterPoint[dp] >= 5,
        finalNumber;

    afterPoint = afterPoint.slice(0, dp);
    if (!shouldRoundUp) {
        finalNumber = beforePoint + '.' + afterPoint;
    } else if (/^9+$/.test(afterPoint)) {
        // If we need to round up a number like 1.9999, increment the integer
        // before the decimal point and discard the fractional part.
        finalNumber = Number(beforePoint)+1;
    } else {
        // Starting from the last digit, increment digits until we find one
        // that is not 9, then stop
        var i = dp-1;
        while (true) {
            if (afterPoint[i] == '9') {
                afterPoint = afterPoint.substr(0, i) +
                             '0' +
                             afterPoint.substr(i+1);
                i--;
            } else {
                afterPoint = afterPoint.substr(0, i) +
                             (Number(afterPoint[i]) + 1) +
                             afterPoint.substr(i+1);
                break;
            }
        }

        finalNumber = beforePoint + '.' + afterPoint;
    }

    // Remove trailing zeroes from fractional part before returning
    return finalNumber.replace(/0+$/, '')
}

사용 예 :

> roundStringNumberWithoutTrailingZeroes(1.6, 2)
'1.6'
> roundStringNumberWithoutTrailingZeroes(10000, 2)
'10000'
> roundStringNumberWithoutTrailingZeroes(0.015, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.015000', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(1, 1)
'1'
> roundStringNumberWithoutTrailingZeroes('0.015', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(0.01499999999999999944488848768742172978818416595458984375, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.01499999999999999944488848768742172978818416595458984375', 2)
'0.01'

위의 함수는 실수로 실수로 반올림 한 숫자를 목격 한 사용자를 피하기 위해 사용하려는 것입니다 .

(대안으로, 거칠게 다른 구현으로 비슷한 동작을하는 함수를 제공하는 github.com/jhohlfeld/round10 라이브러리를 사용해 볼 수도 있습니다.)

그러나 두 번째 종류의 Number를 갖는 경우에는 소수점 이하 자릿수를 사용하는 근사 소수 표현이 더 많은 소수 자릿수 표현보다 정확 하다고 생각할 필요가없는 연속 규모에서 가져온 값입니다. 이 경우, String 표현을 존중하고 싶지 는 않습니다. 그 표현은 (스펙으로 설명되고있는) 이미 일종의 둥근 형태이기 때문에입니다. 우리는 "0.014999999 ... 375 회 돌파하여 0.015까지 돌리며 0.02 돌파하여 0.014999999 ... 375 회 돌파하여 0.02"라고 말하고 싶지 않습니다.

여기서 우리는 단순히 내장 된 toFixed 메소드를 사용할 수 있습니다. toFixed 에 의해 반환 된 String에서 Number() 를 호출하면 Number의 String 표현에 후행 0이없는 Number를 얻습니다 (JavaScript가 Number의 String 표현을 계산하는 방식 덕분에이 답변에서 앞에서 설명 했음).

/**
 * Takes a float and rounds it to at most dp decimal places. For example
 *
 *     roundFloatNumberWithoutTrailingZeroes(1.2345, 3)
 *
 * returns 1.234
 *
 * Note that since this treats the value passed to it as a floating point
 * number, it will have counterintuitive results in some cases. For instance,
 * 
 *     roundFloatNumberWithoutTrailingZeroes(0.015, 2)
 *
 * gives 0.01 where 0.02 might be expected. For an explanation of why, see
 * http://.com/a/38676273/1709587. You may want to consider using the
 * roundStringNumberWithoutTrailingZeroes function there instead.
 *
 * @param {number} num
 * @param {number} dp
 * @return {number}
 */
function roundFloatNumberWithoutTrailingZeroes (num, dp) {
    var numToFixedDp = Number(num).toFixed(dp);
    return Number(numToFixedDp);
}

정밀한 반올림 방법. 출처 : MDN

(function(){

    /**
     * Decimal adjustment of a number.
     *
     * @param   {String}    type    The type of adjustment.
     * @param   {Number}    value   The number.
     * @param   {Integer}   exp     The exponent (the 10 logarithm of the adjustment base).
     * @returns {Number}            The adjusted value.
     */
    function decimalAdjust(type, value, exp) {
        // If the exp is undefined or zero...
        if (typeof exp === 'undefined' || +exp === 0) {
            return Math[type](value);
        }
        value = +value;
        exp = +exp;
        // If the value is not a number or the exp is not an integer...
        if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
            return NaN;
        }
        // Shift
        value = value.toString().split('e');
        value = Math[type](+(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));
    }

    // Decimal round
    if (!Math.round10) {
        Math.round10 = function(value, exp) {
            return decimalAdjust('round', value, exp);
        };
    }
    // Decimal floor
    if (!Math.floor10) {
        Math.floor10 = function(value, exp) {
            return decimalAdjust('floor', value, exp);
        };
    }
    // Decimal ceil
    if (!Math.ceil10) {
        Math.ceil10 = function(value, exp) {
            return decimalAdjust('ceil', value, exp);
        };
    }
})();

예 :

// Round
Math.round10(55.55, -1); // 55.6
Math.round10(55.549, -1); // 55.5
Math.round10(55, 1); // 60
Math.round10(54.9, 1); // 50
Math.round10(-55.55, -1); // -55.5
Math.round10(-55.551, -1); // -55.6
Math.round10(-55, 1); // -50
Math.round10(-55.1, 1); // -60
Math.round10(1.005, -2); // 1.01 -- compare this with Math.round(1.005*100)/100 above
// Floor
Math.floor10(55.59, -1); // 55.5
Math.floor10(59, 1); // 50
Math.floor10(-55.51, -1); // -55.6
Math.floor10(-51, 1); // -60
// Ceil
Math.ceil10(55.51, -1); // 55.6
Math.ceil10(51, 1); // 60
Math.ceil10(-55.59, -1); // -55.5
Math.ceil10(-59, 1); // -50


.toFixed(NumberOfDecimalPlaces) 사용할 수 있습니다.

var str = 10.234.toFixed(2); // => '10.23'
var number = Number(str); // => 10.23

여기에있는 답변 중 어느 것도 맞지 않습니다 . @stinkycheeseman은 모아달라고 요청했다.

반올림하려면 다음을 사용하십시오.

Math.ceil(num * 100)/100;

lodash 라이브러리를 사용하고 있다면, 다음과 같이 round 메소드 인 lodash를 사용할 수 있습니다.

_.round(number, precision)

예 :

_.round(1.7777777, 2) = 1.78


더 간단한 ES6 방법은

const round = (x, n) => 
  parseFloat(Math.round(x * Math.pow(10, n)) / Math.pow(10, n)).toFixed(n);

이 패턴은 요청 된 정밀도를 리턴합니다.

전의:

round(44.7826456, 4)  // yields 44.7826
round(78.12, 4)       // yields 78.1200

일반적으로 반올림은 크기 조정을 통해 수행됩니다. round(num / p) * p

지수 표기법을 사용하면 + 숫자의 반올림을 올바르게 처리 할 수 ​​있습니다. 그러나이 방법은 모서리 케이스를 올바르게 둥글게하지 못합니다.

function round(num, precision = 2) {
	var scaled = Math.round(num + "e" + precision);
	return Number(scaled + "e" + -precision);
}

// testing some edge cases
console.log( round(1.005, 2) );  // 1.01 correct
console.log( round(2.175, 2) );  // 2.18 correct
console.log( round(5.015, 2) );  // 5.02 correct

console.log( round(-1.005, 2) );  // -1    wrong
console.log( round(-2.175, 2) );  // -2.17 wrong
console.log( round(-5.015, 2) );  // -5.01 wrong

여기서는 산술 반올림을 올바르게 수행하기 위해 작성한 함수도 있습니다. 직접 테스트 할 수 있습니다.

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

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


프로토 타입 방법은 다음과 같습니다.

Number.prototype.round = function(places){
    places = Math.pow(10, places); 
    return Math.round(this * places)/places;
}

var yournum = 10.55555;
yournum = yournum.round(2);

ES6 이후부터는 toPrecision사용하여 '적절한'방법 (통계를 재정의하고 해결 방법을 만들지 않고)을 수행합니다.

var x = 1.49999999999;
console.log(x.toPrecision(4));
console.log(x.toPrecision(3));
console.log(x.toPrecision(2));

var y = Math.PI;
console.log(y.toPrecision(6));
console.log(y.toPrecision(5));
console.log(y.toPrecision(4));

var z = 222.987654
console.log(z.toPrecision(6));
console.log(z.toPrecision(5));
console.log(z.toPrecision(4));


MarkG와 Lavamantis는 받아 들여진 것보다 훨씬 나은 해결책을 제시했습니다. 그들이 더 많은 upvotes를 얻지 않는 것은 수치 다!

다음은 MDN 기반 의 부동 소수점 문제를 해결하는 데 사용하는 함수 입니다. Lavamantis의 솔루션보다 훨씬 더 간결합니다 (간결하지는 않습니다).

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(10.8034, 2);      // Returns 10.8
round(1.275, 2);        // Returns 1.28
round(1.27499, 2);      // Returns 1.27
round(1.2345678e+2, 2); // Returns 123.46

Lavamantis의 솔루션에 비해 우리가 할 수있는 ...

round(1234.5678, -2); // Returns 1200
round("123.45");      // Returns 123


+(10).toFixed(2); // = 10
+(10.12345).toFixed(2); // = 10.12

(10).toFixed(2); // = 10.00
(10.12345).toFixed(2); // = 10.12




decimal-point