Javascript에서 소수점 - 재미있는 질문입니다.

프로그래밍에서, 우리는 반드시 10진수를 처리해야 한다. 이것은 결코 보기 드문 것이 아니다. 많은 경우, 표시하거나 다른 목적을 위해서, 우리는 항상 그것들을 반올림해야 한다.
나의 현재 업무 환경에서 나 자신도 이런 문제에 부딪힌 적이 있다. 다음은 내가 어떻게 처리한 것이다.유사한 문제에 직면한 사람들을 도울 수 있기를 바란다.

문제


질문: I have to round off some decimal numbers to a designated decimal points.
예를 들어, 만약 내가 반올림 3 decimal points 을 해야 한다면, 이것은 다음과 같다.
0.1234 --> 0.123
1.2345 --> 1.235 (note the 5 in the end)

솔루션 찾기


이제 진정한 자바스크립트 개발자로서 내가 취한 첫 번째 단계는 당연히 구글에서 그것을 검색하는 것이다.
언뜻 보기에는 .toPrecision() 솔루션인 것 같지만 실제로는 그렇지 않습니다.
Number(0.1234).toPrecision(3) --> 0.123
Number(1.2345).toPrecision(4) --> 1.234
여기서 두 가지 질문을 볼 수 있습니다.
[1] 이것은 내가 필요로 하는 것처럼 off 답안을 반올림하는 것이 아니라 끝에 있는 여분의 숫자를 간단하게 삭제하여 반올림하는 것이다down.
[2] 나는 사용할 정밀도를 확인하기 위해 정수 부분에 몇 개의 유효한 숫자가 있는지 알아야 한다.
그래서 계속 검색할게요.그리고 찾았어요this post.
이 솔루션은 매우 우아하다. 숫자를 10의 어느 멱에 곱한 다음 Math.round() 가장 가까운 정수로 반올림한다.마지막으로 숫자를 10의 같은 멱으로 나누면 정답을 얻을 수 있다.

이 솔루션에 대한 심도 있는 연구


만약 네가 그것의 가장 좋은 답안을 자세히 연구한다면, 너는 재미있는 것 중 하나를 발견할 수 있을 것이다.
이것이 바로 내가 이 문장에서 해석하고 싶은 것이다.
우선, 나는 부동점 알고리즘을 상세하게 소개하지 않을 것이다.만약 당신이 정말 최선을 다하고 싶다면, 여기에 Number.EPSILON 참고할 수 있습니다.
이유를 이해하기 위해 자바스크립트에서 숫자를 어떻게 처리하는지 봅시다.

한 직위 이진 표현법 이해


그중에서 가장 간단한 것은 정수다.계산할 때 바이너리 형식(예:
13 can be represented as 1101 in binary because

1101 (in binary)
= 1 * 2^3 + 1 * 2^2 + 0 * 2^1 + 1 * 2^0
= 8 + 4 + 1
= 13
십진수는 어떻습니까?그것들의 저장 방식은 유사하지만 사용하는 2의 멱은 음멱이다.
0.875 can be represented as 0.111 in binary because

0.111 (in binary)
= 1 * 2^-1 + 1 * 2^-2 + 1 * 2^-3
= 0.5 + 0.25 + 0.125
= 0.875
지금 너는 이 시스템에 문제가 있는 것을 볼 수 있을 것이다.모든 십진수를 이진 형식으로 정확하게 표시할 수 있는 것은 아니다.이것이 바로 우리가 이 이상한 결과를 얻은 이유이다.

이는 0.1과 0.2 모두 2진법으로 정확하게 표시할 수 없기 때문에 그것들의 총계가 정확하지 않기 때문이다.Javascript는 가장 가까운 답을 얻을 수 있도록 최선을 다했는데 결과는 0.3에 가깝다.
앞의 관찰로 돌아가서 왜 우리가 필요로 하는가Number.EPSILON?이것은 우리의 이전 알고리즘에 약간의 변두리 상황이 존재했기 때문이다.그들은 숫자 1.005 의 문제를 제기했다. 반올림이 2개의 소수점에 이르렀을 때, 그것은 1 가 아니라 1.01 로 반올림되었다.

이상한 사건


여기서 우리는 더 재미있는 숫자를 연구하여 원인을 이해했다. 가령 우리가 이 숫자4.975를 2개의 소수점으로 반올림해야 한다고 가정하자.알고리즘은 다음과 같습니다.
1. First, we have 4.975.
2. We multiply it by 100 to get 497.5
3. We perform Math.round(497.5) to get 498
4. We divide it by 100 to get the answer 4.98
이 모든 것이 논리적이고 완벽한 것 같다. 그렇지?Javascript는 다음을 나타냅니다.

왜 이러지?단계별로 테스트를 진행하면 다음을 볼 수 있습니다.

보시다시피 4.975 2진법으로 정확하게 표시할 수 없기 때문에 자바스크립트는 그 값과 비슷하게 하려고 시도했지만 100을 곱한 결과 부족했습니다.
이것이 바로 왜 원시 숫자에 Number.EPSILON - 너무 작아서 실제 값에 영향을 주지 않지만 자바스크립트의 근사값을 정확하게 반올림하는 데 도움이 된다.
그러나
original post
나는 지금 안심하고 stackoverflow의 답이 틀렸다고 말할 수 있다.하하!바로 네 앞에 있어!
그래, 농담하지 마, 우리 지금 이 문제를 어떻게 처리해야 돼?

진정한 솔루션


정교한 해결 방안을 찾을 수 있다 .대략적인 생각은 어떤 조작을 하기 전에 숫자를 정수로 설정하는 것이다.이것은 정수가 Javascript에서 정확하게 표시될 수 있기 때문이다.방법은 다음과 같습니다.
1. Starting with 4.975 again.
2. We multiply 1000 to 4.975 to get 4975, an integer.
3. We now divide it by 10 to get 497.5 for rounding.
4. We perform Math.round(497.5) to get 498.
5. We now divide it by 100 to get 4.98, our final answer.
이것 괜찮아요?맞다
here
왜?2단계에서 우리는 4.975 를 정확하게 나타내는 정수 4975 로 전환했기 때문이다.그것이 10 제거되었을 때, 497.5 지금은 정확하게 표시할 수 있다. 왜냐하면 소수 부분0.5은 2진법으로 정확하게 표시할 수 있기 때문이다.
이 기술은 합리적인 디지털 범위에만 적용됩니다.정수는 오류를 피하기 위해 정확하게 표시할 수 있지만 Javascript가 정수를 위해 보존할 수 있는 비트는 여전히 제한되어 있습니다 - .정수로 변환한 후 숫자가 이 제한을 초과하면 표현에 오류가 발생하고 이 기술은 더 이상 유효하지 않습니다.이런 상황에서 너는 다른 방식을 취해야 할 수도 있다.
지금 이 정도야!이 댓글을 좋아해 주셨으면 좋겠어요!

숫자최대 보안 정수 TL;박사


연산이나 수학을 하기 전에 숫자를 정수로 변환합니다.원형().알고리즘에 대해서는 을 참조하십시오.

좋은 웹페이지 즐겨찾기