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


2757

소수점 이하 두 자리까지 반올림하고 싶지만 필요한 경우에만 .

입력:

10
1.7777777
9.1

산출:

10
1.78
9.1

JavaScript로 어떻게 할 수 있습니까?


22
나는 솔루션으로 제공되는 많은 기술로 바이올린을 만들었습니다 ... 비교 할 수 있습니다 : 바이올린
dsdsdsdsd

37
아무도 모르는 것 같습니다 Number.EPSILON. 사용하십시오 Math.round( num * 100 + Number.EPSILON ) / 100.
cronvel

3
새로운 독자의 경우 string type result가 없으면 이 작업을 수행 할 수 없습니다 . 숫자의 이진 내부 표현에 대한 부동 소수점 수학은 항상 소수로 표현할 수없는 숫자가 있음을 의미 합니다.
Walf

9
@cronvel Number.EPSILON여기서 사용하는 이유를 설명해 주 시겠습니까?
Bruce Sun

5
나는 토끼 구멍을 떨어 뜨리고이 페이지에서 더 흥미로운 답변을 테스트했습니다 (첫 페이지 만). Codepen이 있습니다. 힌트 : 답변에 대한 의견이 많을수록 제대로 작동 할 가능성은 줄어 듭니다.
Adam Jagosz '

답변:


3490

사용하다 Math.round(num * 100) / 100

편집 : 1.005와 같은 것을 올바르게 반올림하기 위해

Math.round((num + Number.EPSILON) * 100) / 100


395
이것은 대부분의 경우에 효과가 있지만 1.005에서는 작동하지 않을 것입니다. 1.005 대신 1이 될 것입니다.
James

83
@James Wow 정말 이상합니다. Chrome 개발자 콘솔에서 작업 중이며 1.005 * 100 = 100.49999999999999입니다. Math.round (100.49999999999999)는 100으로 평가되는 반면 Math.round (100.5)는 101로 평가됩니다. IE9도 같은 작업을 수행합니다. 이것은 자바 스크립트에서 부동 소수점 이상
stinkycheeseman

153
간단한 해결 방법. 2dp의 경우을 사용하십시오 Math.round((num + 0.00001) * 100) / 100. 시도 Math.round((1.005 + 0.00001) * 100) / 100Math.round((1.0049 + 0.00001) * 100) / 100
mrkschan

31
@mrkschan 왜 그렇게 작동하고 모든 숫자에 대한 바보입니까?
CMCDragonkai

86
그것을 얻지 못하는 사람들을 위해이 기술을 스케일링이라고합니다. 기본적으로 대답은 소수점을 가로 질러 두 개의 숫자를 가져 와서 모든 부동 소수점 문제를 피하기 위해 숫자를 정수로 변환 한 다음 반올림 한 다음 100으로 나누어 이전의 상태로 다시 변환하는 것입니다. 2dp에 대답하십시오.
Alex_Nabu

3062

값이 텍스트 유형 인 경우 :

parseFloat("123.456").toFixed(2);

값이 숫자 인 경우 :

var numb = 123.23454;
numb = numb.toFixed(2);

1.5와 같은 값은 "1.50"을 출력으로 제공한다는 단점이 있습니다. @minitech가 제안한 수정 사항 :

var numb = 1.5;
numb = +numb.toFixed(2);
// Note the plus sign that drops any "extra" zeroes at the end.
// It changes the result (which is a string) into a number again (think "0 + foo"),
// which means that it uses only as many digits as necessary.

Math.round더 나은 솔루션 인 것 같습니다 . 그러나 그렇지 않습니다! 어떤 경우에는 올바르게 반올림 되지 않습니다 .

Math.round(1.005 * 1000)/1000 // Returns 1 instead of expected 1.01!

경우에 따라 toFixed ()도 올바르게 반올림 되지 않습니다 (Chrome v.55.0.2883.87에서 테스트)!

예 :

parseFloat("1.555").toFixed(2); // Returns 1.55 instead of 1.56.
parseFloat("1.5550").toFixed(2); // Returns 1.55 instead of 1.56.
// However, it will return correct result if you round 1.5551.
parseFloat("1.5551").toFixed(2); // Returns 1.56 as expected.

1.3555.toFixed(3) // Returns 1.355 instead of expected 1.356.
// However, it will return correct result if you round 1.35551.
1.35551.toFixed(2); // Returns 1.36 as expected.

내 생각에 이것은 1.555가 실제로 배후에 1.55499994 인 플로트와 같은 것이기 때문입니다.

해결 방법 1 은 필요한 반올림 알고리즘이있는 스크립트를 사용하는 것입니다. 예를 들면 다음과 같습니다.

function roundNumber(num, scale) {
  if(!("" + num).includes("e")) {
    return +(Math.round(num + "e+" + scale)  + "e-" + scale);
  } else {
    var arr = ("" + num).split("e");
    var sig = ""
    if(+arr[1] + scale > 0) {
      sig = "+";
    }
    return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale);
  }
}

https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview

참고 : 이것은 모든 사람에게 보편적 인 솔루션은 아닙니다. 몇 가지 다른 반올림 알고리즘이 있으며 구현이 다를 수 있으며 요구 사항에 따라 다릅니다. https://en.wikipedia.org/wiki/Rounding

해결 방법 2 는 프런트 엔드 계산을 피하고 백엔드 서버에서 반올림 된 값을 가져 오는 것입니다.


81
이 (고정 된) 접근 방식은 훌륭하고 저에게 효과적이지만 "필요할 때만"의 원래 요청을 구체적으로 따르지 않습니다 . (1.5에서 1.50으로 반올림하여 사양을 위반합니다.)
Per Lundberg

29
다음 "필요한 경우"요구 사항의 경우,이 할 parseFloat(number.toFixed(decimalPlaces)); @PerLundberg
하기 Onur 디림

36
parseFloat("55.555").toFixed(2)"55.55"Chrome 개발자 콘솔로 돌아갑니다 .
Levi Botelho

22
Math.round 대신 toFixed를 사용하는 이점은 없습니다. toFixed는 똑같은 반올림 문제 (5.555 및 1.005로 시도)를 유발하지만 Math.round보다 500x (농담 없음)와 비슷합니다 ... @MarkG 답변이 더 정확한 것처럼 보입니다.
Pierre

17
toFixed는 "때때로"문자열을 반환하지 않고 항상 문자열을 반환합니다.
McGuireV10

464

당신이 사용할 수있는

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

나는 이것을 MDN 에서 발견했다 . 그들의 방법은 언급 된 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

13
@Redsandro는를 +(val)사용하는 것과 동일 Number(val)합니다. "e-2"를 숫자로 연결하면 문자열을 숫자로 다시 변환해야했습니다.
Jack

41
예를 들어 + "1e-21 + 2"가 올바르게 구문 분석되지 않기 때문에 NaN을 생성하는 크고 작은 플로트의 경우주의하십시오.
Pierre

16
1.005 '문제'를 '해결'했지만 새로운 것을 도입했습니다. 이제 Chrome 콘솔에서 roundToTwo(1.0049999999999999)1.01 (필수적으로 이후 1.0049999999999999 == 1.005)로 표시됩니다. num = 1.005num의 정확한 값이 1.005보다 작기 때문에 '명확하게' 입력 해야하는 부동 소수점 은 1.00으로 반올림됩니다. 물론, 문자열 '1.005' '분명히' '는 1.01로 반올림되어야합니다. 다른 사람들이 실제 올바른 행동이 무엇인지에 대한 다른 직관을 가지고있는 사실은 그것이 왜 복잡한 지의 일부입니다.
Mark Amery

35
1.0049999999999999와 사이에 (부동 소수점) 숫자가 없으므로 1.005정의에 따라 숫자가 동일합니다. 이것을 dedekind cut이라고합니다.
Azmisov

6
@Azmisov가 맞습니다. 동안 1.00499 < 1.005IS true, 1.0049999999999999 < 1.005평가 false.
falconepl

146

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

20
Pierre는 MarkG의 답변에 심각한 문제를 제기했습니다.
dsjoerg

9
참고 : Number.prototype을 변경하지 않으려면 간단히 함수로 작성하십시오. function round(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); }
Philipp Tsipman

2
이것을 확장하는 멋진 방법. 소수점이 음수인지 확인한 다음 e +와 e-를 반전시킬 수 있습니다. 그런 다음 n = 115; n.round (-2); 100을 생산할 것입니다
Lee Louviere

3
시도 n : 1e + 19-그것은 NaN을 반환
DavidJ

3
이 알고리즘은 항상 0이 아닌 반올림합니다. 따라서 음수의 경우 출력이 예상과 (-1.005).round(2) === -1
다릅니다

123

다음을 사용해야합니다.

Math.round( num * 100 + Number.EPSILON ) / 100

아무도 모르는 것 같습니다 Number.EPSILON.

또한 이것은 일부 사람들이 언급 한 것처럼 이상한 JavaScript 가 아니라는 점에 주목할 가치가 있습니다.

그것은 컴퓨터에서 부동 소수점 숫자가 작동하는 방식입니다. 프로그래밍 언어의 99 %와 마찬가지로 JavaScript에는 집에서 만든 부동 소수점 숫자 가 없습니다 . 이를 위해 CPU / FPU에 의존합니다. 컴퓨터는 이진법을 사용하며, 이진법에는와 같은 숫자가 0.1없지만 단순한 이진법이 있습니다. 왜? 같은 이유로 1/3보다 10 진수로 쓸 수 없습니다. 값은 0.33333333입니다. 무한대는 3입니다.

여기로 오세요 Number.EPSILON. 이 숫자는 배정 밀도 부동 소수점 숫자에 존재하는 1과 다음 숫자 의 차이 입니다. 그게 다야 : 1와 1 + 사이에는 숫자가 없습니다 Number.EPSILON.

편집하다:

주석에서 요청했듯이 한 가지를 분명히합시다. Number.EPSILON반올림 할 값이 부동 소수점 오류 델타를 삼킬 수 있기 때문에 반올림 값이 산술 연산의 결과 일 때만 관련이 있습니다.

값이 직접 소스 (예 : 리터럴, 사용자 입력 또는 센서)에서 오는 경우에는 유용하지 않습니다.

편집 (2019) :

@maganap과 일부 사람들이 지적했듯이 Number.EPSILON곱하기 전에 추가하는 것이 가장 좋습니다 .

Math.round( ( num + Number.EPSILON ) * 100 ) / 100

편집 (2019 년 12 월) :

최근에 나는 엡실론을 인식하는 숫자를 비교하기 위해이 기능과 비슷한 기능을 사용합니다.

const ESPILON_RATE = 1 + Number.EPSILON ;
const ESPILON_ZERO = Number.MIN_VALUE ;

function epsilonEquals( a , b ) {
  if ( Number.isNaN( a ) || Number.isNaN( b ) ) {
    return false ;
  }
  if ( a === 0 || b === 0 ) {
    return a <= b + EPSILON_ZERO && b <= a + EPSILON_ZERO ;
  }
  return a <= b * EPSILON_RATE && b <= a * EPSILON_RATE ;
}

내 유스 케이스는 몇 년 동안 개발중인 주장 + 데이터 유효성 검사 라이브러리 입니다.

실제로, 부동 소수점 오류를 누적하기 위해 동등성 검사기를 느슨하게 원하기 때문에 내가 사용하는 코드에서 (엡실론의 네 배) 사용 ESPILON_RATE = 1 + 4 * Number.EPSILON하고 EPSILON_ZERO = 4 * Number.MIN_VALUE있습니다.

지금까지는 나에게 완벽 해 보입니다. 도움이 되길 바랍니다.


1
@palota 당신은 EPSILON cronvel이 언급 한 것처럼 실제 숫자를 정의 할 수 있습니다
Daniel San

3
이것이 정답입니다! 문제 자체는 부동 소수점 수는 없습니다 자바 스크립트에 대해 내부적으로 어떻게 작동하는지와 관련이있다
다니엘 산을

22
실제로는 100을 곱하기 전에 엡실론을 추가해야합니다 Math.round( (num + Number.EPSILON) * 100) / 100. 나는 이것이 올바르게 반올림하는 올바른 방법이라는 것에 동의합니다 (이 질문에서 정확히 질문 한 것은 아니지만).
maganap

2
@cronvel 흠. 네가 옳아; 방향의 선택은 하지 메이크업 감각. 따라서 남은 이의 제기는 귀하의 가치가 "반올림"이라고 생각할 원칙적인 이유가있는 도메인에서 일하는 경우에만이 작업을 수행하는 것이 의미가 있다고 생각합니다. 소수의 소수 자릿수가있는 숫자에 대한 간단한 산술 연산의 결과임을 알고 있다면 0.004999999999999999복합 부동 소수점 오류의 결과 일뿐 이며 수학적으로 올바른 결과는 아마도 0.005 일 것입니다. 센서에서 읽는 경우? 별로.
Mark Amery

1
@marchaos 실패하지 않습니다 : 반은 항상 반올림 됩니다 . 예를 들어 Math.round(1.5)= 2이지만 Math.round(-1.5)= -1입니다. 따라서 이것은 완벽하게 일관됩니다. 여기서 -1000이 -1000.01보다 큰 것처럼 -1은 -2보다 큽니다. 더 큰 절대 숫자 와 혼동하지 마십시오 .
cronvel

84

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

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

4
또한 후행 0을 추가하기 때문에 원래 질문에서 요청한 것이 아닙니다 .
Alastair Maw

2
그러나 후행 0 쉽게 정규식으로 제거됩니다, 즉 '수 (10.10000.toFixed (2) .replace (/ 0 + $ /,' '))`=> 10.1
차드

1
@daniel 최고의 답변 은 (현재) 동일하지만 항상 올바르게 반올림 되지 않습니다 . 대신 +(1.005).toFixed(2)어떤 리턴을 시도하십시오 . 11.01
Emile Bergeron

3
@ChadMcElligott : 정규 표현식이 정수와 잘 작동하지 않습니다 : Number(9).toFixed(2).replace(/0+$/, '')=> "9."
Jacob van Lingen

이것이 둥글 지 않은 것 같습니다. 기본적으로 잘립니다. 어떤 경우에는 충분합니다! 감사.
iedmrc

78

이 질문은 복잡합니다.

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

  • 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는 정확히 중간에 있기 때문에) 그들과 같은 숫자가 반올림되는 수학적 규칙이 있습니다).

당신이 짐작 할 수있다 캐치는 점이다 roundTo2DP 가능하게 할 수 그것을 전달되는 모든 세 개의 숫자이기 때문에, 그 명백한 해답을 제공하도록 구현 될 같은 번호 . IEEE 754 이진 부동 소수점 숫자 (JavaScript에서 사용되는 종류)는 대부분의 정수가 아닌 숫자를 정확하게 나타낼 수 없으므로 위의 세 숫자 리터럴은 모두 근처의 유효한 부동 소수점 숫자로 반올림됩니다. 이 숫자는 발생하는 대로 정확하게

0.01499999999999999944488848768742172978818416595458984375

0.02보다 0.01에 가깝습니다.

브라우저 콘솔, 노드 셸 또는 기타 JavaScript 인터프리터에서 세 숫자가 모두 같은 것을 알 수 있습니다. 그냥 그들을 비교하십시오 :

> 0.014999999999999999 === 0.0150000000000000001
true

제가 글을 쓸 때 m = 0.0150000000000000001, 그로m 끝나는 정확한 가치실제0.01 보다 더 가깝습니다 0.02. 그러나 mString으로 변환 하면 ...

> 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 : ToString이 Number 유형에 적용됨 섹션에 있습니다. 여기에 일부 숫자 m 을 문자열 로 변환하는 규칙 이 정리되어 있습니다. 핵심 부분은 포인트 5이며, m 의 문자열 표현에 숫자가 사용될 정수 s 가 생성됩니다 .

있도록 N , K를 , 및 s의 정수가되도록 수행 K ≥ 1, 10 K -1S <10 K 에 대한 숫자 값 S × 10 N - K는mk는 가능한 한 작게한다. 이 K의 소수 표현 자리수 유의 S , S를 10로 나누어 아니고, 최하위 디지트 것을 반드시 고유 이러한 기준에 의해 결정되지 않는다.

여기서 중요한 부분은 " k 는 가능한 한 작아야 "한다는 요구 사항입니다 . 그 요구 사항 m의 가치 는 Number가 주어지면 의 요구 사항을 충족하면서도 가능한 최소 자릿수String(m)가져야 한다는 요구 사항입니다 . 우리는 이미 그것을 알고 있기 때문에 , 왜 사실이어야 하는지 분명 합니다.Number(String(m)) === m0.015 === 0.0150000000000000001String(0.0150000000000000001) === '0.015'

물론,이 토론의 아무도는 직접 어떤 대답하지 않았다 roundTo2DP(m) 해야 돌아갑니다. 경우 m'의 정확한 값이 0.01499999999999999944488848768742172978818416595458984375이지만, 그것의 String 표현은'0.015, 그 다음 무엇이며 올바른 수학적, 실제적으로, 철학적으로, 또는 무엇 이건 - - 대답은 우리는 두 개의 소수 자릿수로 반올림 할 때?

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

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

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

이 두 가지 접근 방식에는 다른 코드가 필요합니다. 숫자의 문자열 표현을 존중하기 위해 (합리적으로 약간의 미묘한 코드를 사용하여) 학교에서 사용했을 때와 동일한 알고리즘을 사용하여 숫자로 숫자로 문자열 표현에 직접 작용하는 자체 반올림을 구현할 수 있습니다 숫자를 반올림하는 방법을 배웠습니다. 다음은 소수점 이하의 후행 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://stackoverflow.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'

위의 기능은 사용자가 입력 한 숫자가 잘못 반올림되는 것을 방지하기 위해 사용하려는 것일 수 있습니다.

(대안으로, 다른 구현으로 비슷하게 동작하는 기능을 제공하는 round10 라이브러리를 사용해 볼 수도 있습니다 .)

그러나 두 번째 종류의 숫자-연속 스케일에서 가져온 값을 사용하면 소수점 이하 자릿수가 적은 근사 소수를 더 많이 나타내는 것보다 더 정확 하다고 생각할 이유가 없습니다 . 이 경우, 우리 String 표현을 존중하고 싶지 않습니다. 그 표현은 (사양에서 설명 된 바와 같이) 이미 반올림 되었기 때문입니다. "0.014999999 ... 375는 0.015로 반올림하여 0.02로 반올림하므로 0.014999999 ... 375는 0.02로 반올림"하는 실수를 저지르고 싶지 않습니다.

여기서 우리는 단순히 내장 toFixed방법을 사용할 수 있습니다 . 에 의해 Number()반환 된 String 을 호출 하면 String toFixed표현에 후행 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://stackoverflow.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);
}

일부 경우에는 작동하지 않습니다 . ( jsfiddle )을 사용해보십시오 roundStringNumberWithoutTrailingZeroes(362.42499999999995, 2). 예상 결과 (PHP에서와 같이 echo round(362.42499999999995, 2)) : 362.43. 실제 결과 :362.42
Dr. Gianluigi Zane Zanettini

1
@ Dr.GianluigiZaneZanettini Huh. 기묘한. 왜 PHP round가 362.43을 제공 하는지 잘 모르겠습니다 . 362.42499999999995가 362.425 (수학 및 코드-JS 362.42499999999995 < 362.425와 PHP 모두에 해당) 보다 작기 때문에 직관적으로 잘못된 것 같습니다 . PHP의 대답은 원래와 둥근 부동 소수점 숫자 사이의 거리를 최소화하지도 않습니다 362.43 - 362.42499999999995 > 362.42499999999995 - 362.42. php.net/manual/en/function.round.php 에 따르면 , PHP round는 C99 표준을 따릅니다. 나는 무슨 일이 일어나고 있는지 이해하기 위해 C의 땅으로 모험을해야합니다.
Mark Amery

1
PHP의 소스에서 반올림 구현 을 살펴본 후 , 나는 그것이 무엇을하고 있는지 전혀 모른다. 매크로와 브랜치, 문자열 변환 및 하드 코딩 된 마법 정밀도 값으로 브랜치로 구성된 끔찍한 복잡한 구현입니다. "PHP의 답변이 명백히 잘못되었으므로 버그 보고서를 제출해야합니다."이외의 말을 잘 모르겠습니다. 그런데 362.42499999999995라는 숫자를 어떻게 찾았습니까?
Mark Amery

1
@ Dr.GianluigiZaneZanettini 버그 보고서를 만들었습니다 : bugs.php.net/bug.php?id=75644
Mark Amery

2
@ Dr.GianluigiZaneZanettini "말이 되나요?" - 아니; 반올림이 작동하는 방식이 아닙니다. 1.000005는 5로 끝나지 만 가장 가까운 정수로 반올림되면 답은 2가 아닌 1이어야합니다. 마찬가지로 1499995는 5로 끝나지 만 가장 가까운 백만으로 반올림하면 결과는 2000000이 아닌 1000000이어야합니다. 362.42499999999995의 경우 2 DP로 반올림되는 경우 반올림 방향을 결정해야하는 것은 소수점 이하 3 자리입니다. 4
Mark Amery

76

고려 .toFixed()하고 .toPrecision():

http://www.javascriptkit.com/javatutors/formatnumber.shtml


1
toFixed는 모든 값에 소수점을 추가합니다.
stinkycheeseman

13
둘 다 여기 쓸모가 없다
Esailija

불행히도 두 함수 모두 @stinkycheeseman이 원하지 않는 것처럼 소수점 자리를 추가합니다.
jackwanders 2012 년


2
숫자가 아닌 문자열을 반환하므로 서식이 지정되고 계산되지 않습니다.
saimiris_devel

63

정확한 반올림 방법. 출처 : Mozilla

(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

누군가 이것을 GitHub와 npm에도 넣었
Jo Liss

아니, Math.round10(3544.5249, -2)3544.52 대신 3544.53 반환
마티

2
@Matija Wolfram alpha 도 3544.52를 말합니다. 현재 수와 반올림 근사값 간의 오차를 최소화하려고합니다. 3544.5249소수점 이하 2 자리에 가장 가까운 근사값 은 3544.52(오류 = 0.0049)입니다. 인 경우 3544.53오류는 0.0051입니다. 연속 반올림을 수행합니다 (예 : Math.round10 (Math.round10 (3544.5249, -3), -2)). 더 큰 반올림 오류가 발생하므로 바람직하지 않습니다.
사용자

3
@Matija, 수학적 관점에서, 3544.5249는 3544.53이 아니라 3544.52이므로이 코드는 정확합니다. 이 경우 3544.53으로 반올림하기를 원하고 이와 같은 경우 (심지어 터프한 경우도 올바르지 않음) 다음과 같이하십시오.number += 0.00011
Bozidar Sikanjic

@ Matia : 함수가 정상적으로 작동한다고 생각합니다. 어쩌면 다음과 같이 반올림을 반복하고 싶을 수도 있습니다.Math.round10( Math.round10(3544.5249, -3) , -2)
jumxozizi

60

여기서 찾은 답변 중 올바른 것은 없습니다 . @stinkycheeseman가하도록 요청 반올림 하면 모든 숫자를 반올림.

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

Math.ceil(num * 100)/100;

15
예제 입력 및 출력은 질문에 'round up ...'이라고 말했지만 실제로는 'round to ...'입니다.
JayDM

2
천장을 만들다가처럼 @stinkycheeseman 특정 케이스에 오류를 지적하고, 그는 항상 라운드까지하고 싶지 않았다, 그는 단지 0.01 모아 0.005 원
mjaggard

9
1.1 * 100은 Firefox, Chrome, Safari 및 Opera ... IE의 최신 최신 브라우저에 따라 오래된 방식으로 생각 하기 때문에 Math.ceil(1.1 * 100)/100;-it 리턴 을 테스트하는 동안 이상한 버그가 발견 되었습니다 . 1.11110.000000000000011.1*100=1100
skobaljic

1
@skobaljic tryMath.ceil(num.toFixed(4) * 100) / 100
treeface

1
@treeface Math.ceil((1.1).toFixed(4) * 100) / 1001.11Firefox 에서도 반환 됩니다. 현대 브라우저 문제 / 버그는 곱셈이며 사람들은 그것에 대해 알아야합니다 (예를 들어 그 당시 복권 게임에서 일했습니다).
skobaljic

47

간단한 방법은 다음과 같습니다.

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

2
이 솔루션은 잘못되었습니다. stackoverflow.com/questions/38322372/…를 참조하십시오. 156893.145를 입력하고 위의 함수로 반올림하면 156893.15 대신 156893.14를 얻습니다 !!!
saimiris_devel

2
@saimiris_devel, JavaScript에서 숫자의 숫자 표현이 실패하는 인스턴스를 찾았습니다. 올바로 반올림되는 것이 맞습니다. 그러나-100을 곱한 샘플 번호가 이미 깨져 있기 때문입니다 (15689314.499999998). 실제로 완전한 기능을 갖춘 답변에는 JavaScript에서 실수를 처리 할 때의 불일치를 고려하기 위해 특별히 개발 된 라이브러리가 필요합니다. 그렇지 않으면이 질문에 대한 답변을 무효화 할 수 있습니다.
JayDM

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

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

1
이것은 당신이 당신의 숫자의 문자열 표현을 취하고 반올림했을 때 얻을 수있는 것과 같은 결과를 항상 제공하지는 않습니다. 예를 들면 다음과 같습니다 +(0.015).toFixed(2) == 0.01.
Mark Amery

35

나에게 Math.round () 는 정답을주지 못했습니다. toFixed (2) 가 더 잘 작동 한다는 것을 알았습니다 . 아래는 두 가지 예입니다.

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

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


toFixed는 반올림을 수행하지 않으며 Math.round는 가장 가까운 정수로 반올림합니다. 따라서 소수점을 유지하려면 원래 숫자에 원하는 10 진수를 나타내는 0의 10의 거듭 제곱 수를 곱한 다음 결과를 같은 숫자로 나누어야합니다. 귀하의 경우 : Math.round (43000 / 80000 * 100 * 100) / 100. 마지막으로 결과에 항상 소수점 이하 두 자리 (필요한 곳에 0이 있음)를 보장하기 위해 고정 (2)가 적용될 수 있습니다. 세로로 표시된 일련의 숫자를 오른쪽 정렬하기 위해 :)
Turbo

7
또한 .toFIxed ()는 숫자가 아닌 문자열을 출력합니다.
carpiediem 2016 년

2
그래도에 대한 반올림을 해결하지 못합니다 1.005. (1.005).toFixed(2)여전히 결과 1.00.
DPac

34

이 기능을 사용하십시오 Number(x).toFixed(2);


8
Number문자열로 반환하지 않으려면 다시 모두 감싸십시오 .Number(Number(x).toFixed(2));

5
Number호출은 필요하지 않습니다 x.toFixed(2)작동합니다.
bgusach

3
@bgusach 문 x.toFixed (2)는 숫자가 아닌 문자열을 반환하므로 숫자 호출이 필요합니다. 다시 숫자로 변환하려면 Number
Mohan Ram

2
이 방법을 사용하면이 (1).toFixed(2)반환 1.00되지만 질문자에게는 1이 질문이 필요합니다 .
Eugene Mala

1
이것은 작동하지 않습니다 1.005.toFixed(2)수율 "1"이해야 할 때 "1.01".
Adam Jagosz '

33

2017
네이티브 코드 만 사용.toFixed()

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

엄격해야하고 필요한 경우 숫자를 추가하면 사용할 수 있습니다. replace

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

3
toFixed 메소드는 문자열을 리턴합니다. 숫자 결과를 원하면 tose의 결과를 parseFloat로 보내야합니다.
잠보 닐리

@Zambonilli 또는 필요한 경우 1을 곱하십시오. 고정 된 수의 대부분의 경우는 표시하지 계산 문자열되어 있기 때문에 올바른 형식은
미몬 pery

2
-1; toFixed몇 년 전에 여러 번의 답변 으로 제안되었을뿐만 아니라 질문의 "필요한 경우에만"조건을 충족시키지 못합니다. asker가 원하는 곳을 (1).toFixed(2)제공 "1.00"합니다 "1".
Mark Amery

알았어 나는 그 사건에 대한 일부 솔루션을 추가
pery을 미몬

lodash를 사용하는 경우 훨씬 쉽습니다. _.round (number, decimalPlace) 마지막 주석을 삭제했습니다. cuz에 문제가 있습니다. 그러나 Lodash ..round는 작동합니다. 소수점 이하 자릿수가 2 인 1.005는 1.01로 변환됩니다.
데빈 필드

32

경량 솔루션을 사용해보십시오 .

function round(x, digits){
  return parseFloat(x.toFixed(digits))
}

 round(1.222,  2) ;
 // 1.22
 round(1.222, 10) ;
 // 1.222

이 사이에 차이가 있는지 아는 사람이 return Number(x.toFixed(digits))있습니까?

1
@JoeRocc ... .toFixed()어쨌든 숫자 만 허용 하므로 내가 볼 수있는 한 아무런 차이가 없어야합니다 .
petermeissner

4
이 답변은이 페이지에서 여러 번 언급 한 것과 같은 문제가 있습니다. 대신 대신 round(1.005, 2)결과를 보십시오 . 11.01
MilConDoin

반올림 알고의 문제가 더있는 것 같습니까? -하나 이상의 상상이있을 것입니다 : en.wikipedia.org/wiki/Rounding ... round(0.995, 2) => 0.99; round(1.006, 2) => 1.01; round(1.005, 2) => 1
petermeissner

31

몇 가지 방법이 있습니다. 나와 같은 사람들에게 Lodash의 변형

function round(number, precision) {
    var pair = (number + 'e').split('e')
    var value = Math.round(pair[0] + 'e' + (+pair[1] + precision))
    pair = (value + 'e').split('e')
    return +(pair[0] + 'e' + (+pair[1] - precision))
}

용법:

round(0.015, 2) // 0.02
round(1.005, 2) // 1.01

프로젝트가 jQuery 또는 lodash를 사용 round하는 경우 라이브러리에서 적절한 방법을 찾을 수도 있습니다 .

업데이트 1

변형 n.toFixed(2)이 올바르지 않기 때문에 제거했습니다 . 감사합니다 @ avalanche1


두 번째 옵션은 정확히 두 개의 소수점이있는 문자열을 반환합니다. 질문은 필요한 경우에만 소수점을 요구합니다. 이 경우 첫 번째 옵션이 더 좋습니다.
Marcos Lima

@MarcosLima Number.toFixed()는 문자열을 반환하지만 그 앞에 더하기 기호가 있으면 JS 인터프리터는 문자열을 숫자로 변환합니다. 이것은 구문 설탕입니다.
stanleyxu2005

Firefox alert((+1234).toFixed(2))에서는 "1234.00"을 표시합니다.
Marcos Lima

Firefox에서는을 alert(+1234.toFixed(2))던집니다 SyntaxError: identifier starts immediately after numeric literal. 나는 첫 번째 옵션을 고수합니다.
Marcos Lima

일부 경우에는 작동하지 않습니다 . ( jsfiddle )을 사용해보십시오 362.42499999999995. 예상 결과 (PHP에서와 같이 echo round(362.42499999999995, 2)) : 362.43. 실제 결과 :362.42
Dr. Gianluigi Zane Zanettini

26

lodash 라이브러리를 사용하는 경우 다음과 같이 lodash의 라운드 방법을 사용할 수 있습니다.

_.round(number, precision)

예 :

_.round(1.7777777, 2) = 1.78

@Peter Lodash가 제공하는 기능 세트는 표준 Javascript와 비교하여 정말 좋습니다. 그러나 Lodash에는 표준 JS와 비교할 때 성능 문제가 있다고 들었습니다. codeburst.io/…
Madura Pradeep

1
lodash를 사용하면 성능 단점이 있다는 점에 동의합니다. 이러한 문제는 많은 추상화에 공통적이라고 생각합니다. 그러나이 스레드에 대한 답변의 수와 에지 사례에 대한 직관적 인 솔루션이 어떻게 실패하는지 살펴보십시오. jQuery에서이 패턴을 보았으며 브라우저가 대부분의 사용 사례를 해결하는 공통 표준을 채택했을 때 근본 문제가 해결되었습니다. 그런 다음 성능 병목 현상이 브라우저 엔진으로 이동되었습니다. 나는 똑같은 일이 일어나야한다고 생각합니다. :)
Peter

26

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

그러면 그냥 parseFloat제로가 사라질 것입니다.

console.log(parseFloat((1.4999).toPrecision(3)));
console.log(parseFloat((1.005).toPrecision(3)));
console.log(parseFloat((1.0051).toPrecision(3)));

'1.005 반올림 문제'는 해결하지 못합니다 . 부동 소수점이 처리되는 방식에 내재되어 있기 때문입니다 .

console.log(1.005 - 0.005);

라이브러리가 열려 있으면 bignumber.js 를 사용할 수 있습니다

console.log(1.005 - 0.005);
console.log(new BigNumber(1.005).minus(0.005));

console.log(new BigNumber(1.005).round(4));
console.log(new BigNumber(1.005).round(3));
console.log(new BigNumber(1.005).round(2));
console.log(new BigNumber(1.005).round(1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/bignumber.js/2.3.0/bignumber.min.js"></script>


3
(1.005).toPrecision(3)실제로 1.00대신에 여전히 반환 합니다 1.01.
Giacomo

toPrecision원하는 출력 유형을 변경하는 문자열을 반환합니다.
adamduren

@Giacomo이 .toPrecision방법 은 결함이 아니며 부동 소수점 숫자 (JS의 숫자)의 특이성입니다 . 시도 1.005 - 0.005하면을 반환 0.9999999999999999합니다.
shau-kote

1
(1).toPrecision(3)'1.00'을 반환하지만 질문자는 1이 경우에 원했습니다 .
Eugene Mala

1
@Giacomo가 말했듯 이이 대답은 "유효 숫자"와 "소수 자릿수로 반올림"을 혼동하는 것으로 보입니다. toPrecision형식은 후자가 아니라 형식을 수행하며 OP의 질문에 대한 답변이 아닙니다. 처음에는 관련성이있는 것처럼 보일 수 있지만 많이 잘못됩니다. en.wikipedia.org/wiki/Significant_figures를 참조하십시오 . 예를 들어,를 Number(123.4).toPrecision(2)반환 "1.2e+2"하고 Number(12.345).toPrecision(2)반환합니다 "12". 또한 @adamduren의 견해에 따르면 바람직하지 않은 문자열 (거대한 문제는 아니지만 바람직하지 않음)을 반환한다는 데 동의합니다.
Neek

23

MarkG와 Lavamantis는 수용된 것보다 훨씬 나은 솔루션을 제공했습니다. 그들이 더 많은지지를 얻지 못하는 것은 부끄러운 일입니다!

다음은 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

2
귀하의 솔루션은 MDN 솔루션과 달리 일부 사례를 다루지 않습니다. 짧을 수도 있지만 정확하지는 않습니다.
astorije

1
round (-1835.665,2) => -1835.66
Jorge


18

가장 쉬운 방법은 toFixed를 사용하고 Number 함수를 사용하여 후행 0을 제거하는 것입니다.

const number = 15.5;
Number(number.toFixed(2)); // 15.5
const number = 1.7777777;
Number(number.toFixed(2)); // 1.78

모든 경우에 해당되는 것은 아닙니다. 답변을 게시하기 전에 광범위한 테스트를 수행하십시오.
baburao

@baburao 위의 해결 방법으로 문제가 해결되지 않는 경우를 게시 해주세요
Marcin Wanago

const 번호 = 15; 숫자 (숫자에서 고정됨 (2)); 15 대신 //15.00
Kevin Jhangiani

1
@KevinJhangiani const 수 = 15; 숫자 (숫자에서 고정됨 (2)); // 15 - 나는 최신 크롬과 파이어 폭스에 모두 테스트
마르신 Wanago

@KevinJhangiani 어떻게 얻 15.00습니까? JS의 숫자 는 소수점 이하 자릿수를 저장 하지 않으며 모든 디스플레이는 초과 소수점 자릿수 (끝의 0)를 자동으로 자릅니다.
VLAZ

16
var roundUpto = function(number, upto){
    return Number(number.toFixed(upto));
}
roundUpto(0.1464676, 2);

toFixed(2) 여기 2는이 숫자를 반올림 할 자릿수입니다.


이 .toFixed ()는 구현하기가 더 간단합니다. 한 번만 통과하면됩니다.
Ritesh Dhuri


14

가장 쉬운 방법:

+num.toFixed(2)

문자열로 변환 한 다음 다시 정수 / 부동 소수점으로 변환합니다.


이 가장 간단한 답변에 감사드립니다. 그러나 + num에서 '+'는 무엇입니까? 십진수 val이 문자열로 나온 곳에서는 작동하지 않았습니다. 나는 : (num * 1) .toFixed (2).
Ethan

@momo 그냥 인수 toFixed()를 3으로 변경하십시오 +num.toFixed(3). 1.005는 1.00으로 반올림되어 1과 같습니다.
bigpotato

1
@Edmund 그것은 1.00이 아닌 1.01을 반환해야합니다
mmm

13

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

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

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

13

"parseFloat (parseFloat (value) .toFixed (2))"와 같은 것을 사용하십시오.

parseFloat(parseFloat("1.7777777").toFixed(2))-->1.78 
parseFloat(parseFloat("10").toFixed(2))-->10 
parseFloat(parseFloat("9.1").toFixed(2))-->9.1

1
부정확성이 float 표현에 본질적인 것이 아니라면 아닙니다. 당신은 그것을 제거한 다음 다시 부동으로 다시 변환하여 동일한 오류를 다시 소개합니다!
Ben McIntyre

12

필요한 경우에만 이러한 반올림을 달성하는 한 가지 방법 은 Number.prototype.toLocaleString () 을 사용하는 것입니다 .

myNumber.toLocaleString('en', {maximumFractionDigits:2, useGrouping:false})

이렇게하면 원하는 결과를 정확하게 얻을 수 있지만 문자열로 표시됩니다. 예상 한 데이터 유형이 아닌 경우 숫자를 다시 숫자로 변환 할 수 있습니다.


이것은 가장 깨끗한 솔루션이며 복잡한 부동 소수점 문제를 모두 회피하지만 MDN 당 지원은 여전히 ​​불완전합니다. Safari는 toLocaleString아직 인수 전달을 지원하지 않습니다 .
Mark Amery

@MarkAmery 현재로서는 Android 브라우저에만 문제가 있습니다. caniuse.com/#search=toLocaleString
ptyskju

12

정확한 정확한 10 진수 반올림 정밀도를 달성하기 위해 가능한 모든 방법을 다양하게 반복 한 후에 가장 정확하고 효율적인 솔루션은 Number.EPSILON을 사용하는 것입니다. 이것은 부동 소수점 수학 정밀도 문제에 대한 진정한 수학 솔루션을 제공합니다. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON 과 같이 쉽게 폴리 필 할 수 있습니다. 어쩌면에게 다시 우리를 마지막으로 남아있는 IE 사용자 모두를 (지원하기 위해 그만해야합니다).

https://stackoverflow.com/a/48850944/6910392에 제공된 솔루션에서 채택되었습니다.

전체 라이브러리를 추가하지 않고도 선택적 정밀도 변수를 사용하여 정확한 10 진수 반올림, 바닥 및 천장을 제공하는 간단한 솔루션 드롭

업데이트 : Sergey가 의견에서 언급했듯이 지적 할 가치가있는이 (또는 다른) 방법에는 제한이 있습니다. 0.014999999999999999와 같은 숫자의 경우에도 부동 소수점 값 저장에 대한 정확도 한계의 절대 한계에 도달 한 결과로 부정확성이 발생합니다. 값 자체가 즉시 0.015로 평가되므로이를 설명하기 위해 적용 할 수있는 수학 또는 기타 솔루션은 없습니다. 콘솔에서 자체적으로 해당 값을 호출하여이를 확인할 수 있습니다. 이 제한으로 인해 문자열 표현이 단순히 "0.015"이므로 문자열 조작을 사용하여이 값을 줄이는 것도 불가능합니다. 이를 설명하기위한 모든 솔루션은 값을 스크립트에 적용하기 전에 데이터 소스에 논리적으로 적용되어야합니다.

var DecimalPrecision = (function(){
        if (Number.EPSILON === undefined) {
            Number.EPSILON = Math.pow(2, -52);
        }
        this.round = function(n, p=2){
            let r = 0.5 * Number.EPSILON * n;
            let o = 1; while(p-- > 0) o *= 10;
            if(n < 0)
                o *= -1;
            return Math.round((n + r) * o) / o;
        }
        this.ceil = function(n, p=2){
            let r = 0.5 * Number.EPSILON * n;
            let o = 1; while(p-- > 0) o *= 10;
            if(n < 0)
                o *= -1;
            return Math.ceil((n + r) * o) / o;
        }
        this.floor = function(n, p=2){
            let r = 0.5 * Number.EPSILON * n;
            let o = 1; while(p-- > 0) o *= 10;
            if(n < 0)
                o *= -1;
            return Math.floor((n + r) * o) / o;
        }
        return this;
    })();
    console.log(DecimalPrecision.round(1.005));
    console.log(DecimalPrecision.ceil(1.005));
    console.log(DecimalPrecision.floor(1.005));
    console.log(DecimalPrecision.round(1.0049999));
    console.log(DecimalPrecision.ceil(1.0049999));
    console.log(DecimalPrecision.floor(1.0049999));
    console.log(DecimalPrecision.round(2.175495134384,7));
    console.log(DecimalPrecision.round(2.1753543549,8));
    console.log(DecimalPrecision.round(2.1755465135353,4));


1
(DecimalPrecision.round (0.014999999999999999, 2)) //
Sergey

잘 잡아! 문제는 JS의 부동 소수점 스토리지에 관한 것입니다. 항상 몇 가지 중요한 경우가 있습니다. 좋은 소식은 Number.EPSILON에 적용한 수학을 먼저 조정하여 해당 엣지 케이스를 엣지로 더 밀어 낼 수 있다는 것입니다. 엣지 케이스에 대한 가능성을 보장하지 않으려면 유일한 해결책은 문자열 조작과 수학입니다. 값에 대해 수학적 계산을 수행하는 순간 (소수점을 이동하려고하더라도) 이미 버그를 생성 한 것입니다.
KFish

실제로, 추가 검사에서 이는 관련된 수학으로 인한 것이 아니라 지정된 값을 호출하면 즉시 문제가 나타납니다. 콘솔에 해당 번호를 입력하면이를 즉시 확인할 수 있으며 즉시 0.015로 평가됩니다. 따라서 이것은 JS의 부동 소수점 숫자에 대한 절대 정확도 가장자리를 나타냅니다. 이 경우 문자열 값이 "0.015"
이므로

11

이것은 가장 간단하고 우아한 솔루션입니다 (그리고 나는 세계 최고입니다).

function roundToX(num, X) {    
    return +(Math.round(num + "e+"+X)  + "e-"+X);
}
//roundToX(66.66666666,2) => 66.67
//roundToX(10,2) => 10
//roundToX(10.904,2) => 10.9

4
그것은 E표기법을 사용하여 인수를 수락하기 위해 허용 된 답변을 다시 쓰는 좋은 방법 입니다.
AxelH

1
일부 경우에는 작동하지 않습니다. try ( jsfiddle ) roundToX(362.42499999999995, 2). 예상 결과 (PHP에서와 같이 echo round(362.42499999999995, 2)) : 362.43. 실제 결과 :362.42
Dr. Gianluigi Zane Zanettini

6
IMHO, PHP 결과가 잘못되었습니다. 세 번째 소수점 다음에 오는 것과 상관없이, 세 번째 소수점이 5보다 작은 경우 두 번째 소수점은 동일하게 유지되어야합니다. 이것이 수학적 정의입니다.
Soldeplata Saketos

1
더 간결한 "e +"는 대신 "e"일 수 있습니다.
Lonnie Best
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.