두 가지 질문을 먼저 살펴 보겠습니다.
0.1 + 0.2 == 0.3; // 거짓
9999999999999999999 == 1000000000000000000; // 진실
첫 번째 문제는 업계의 많은 블로그에서 논의 된 소수점의 정확성입니다. 두 번째 문제는 작년에 체계적인 데이터베이스가 데이터를 수정했을 때 일부 데이터가 복제 된 것으로 나타났습니다. 이 기사는 표준에서 시작하여 위의 문제를 요약합니다.
최대 정수
JavaScript의 숫자는 IEEE 754 Double Precision 64 비트 플로팅 포인트 번호를 사용하여 저장되며 해당 형식은 다음과 같습니다.
sxmx 2^e
S는 부호 비트이며 양수와 부정적인 것을 나타냅니다. M은 52 비트의 Mantissa입니다. E는 지수이며 11 비트입니다. ECMAScript 사양에서 e에 의해 주어진 범위는 [-1074, 971]입니다. 이런 식으로, JavaScript가 표현할 수있는 최대 정수는 다음과 같습니다.
1 x (2^53-1) x 2^971 = 1.7976931348623157E+308
이 값은 숫자입니다 .max_value
마찬가지로 숫자 값 .min_value 값은 다음과 같이 추론 할 수 있습니다.
1 x 1 x 2^(-1074) = 5e-324
Min_Value는 가장 작은 숫자가 아니라 0에 가장 가까운 양수를 나타냅니다. 가장 작은 숫자는 -number.max_value입니다
소수점의 정확도는 손실됩니다
JavaScript 번호는 이중 정제 부동산 지점 숫자이며 컴퓨터의 이진에 저장됩니다. 유의미한 비트 수가 52 비트를 초과하면 정확도 손실이 발생합니다. 예를 들어:
10 진수의 이진은 0.0 0011 0011 0011… (루프 0011)입니다.
10 진수의 이진은 0.0011 0011 0011… (루프 0011)입니다.
0.1 + 0.2 첨가는 다음과 같이 표현 될 수 있습니다.
e = -4; M = 1.10011001100 ... 1100 (52 비트)
+ e = -3; M = 1.10011001100 ... 1100 (52 비트)
--------------------------------------------------------------------------------------------------------------------------------
e = -3; M = 0.11001100110 ... 0110
+ e = -3; M = 1.10011001100 ... 1100
--------------------------------------------------------------------------------------------------------------------------------
e = -3; M = 10.01100110011 ... 001
--------------------------------------------------------------------------------------------------------------------------------
= 0.01001100110011 ... 001
= 0.300000000000000000004 (소수점)
위의 계산을 기반으로, 우리는 또한 결론을 도출 할 수 있습니다. 이진 표현의 소수점 소수의 유한 수가 52 비트를 초과하지 않으면 JavaScript에 정확하게 저장 될 수 있습니다. 예를 들어:
0.05 + 0.005 == 0.055 // true
다음과 같은 추가 규칙
0.05 + 0.2 == 0.25 // true
0.05 + 0.9 == 0.95 // false
IEEE 754의 반올림 모드를 고려해야하며 관심있는 사람들은 더 이상 연구 할 수 있습니다.
큰 정수의 정확도가 손실됩니다
이 질문은 거의 언급되지 않습니다. 첫째, 우리는 문제가 무엇인지 알아 내야합니다.
1. JavaScript가 저장할 수있는 최대 정수는 무엇입니까?
이 질문은 앞서 답변되었으며 숫자입니다.
2. JavaScript가 정밀도를 잃지 않고 저장할 수있는 최대 정수는 무엇입니까?
sxmx 2^e에 따르면, 부호 비트는 양수이고, 52 비트 mantissa는 1으로 완전히 패딩되어 있으며 지수 e는 971의 최대 값입니다. 분명히 대답은 여전히 숫자입니다 .max_value.
우리의 문제는 정확히 무엇입니까? 시작 코드로 돌아 가기 :
9999999999999999999 == 1000000000000000000; // 진실
16 9s는 308 10보다 훨씬 적다는 것은 분명합니다. 이 문제는 max_value와 아무 관련이 없으며 52 자리 만있는 Mantis M에 기인해야합니다.
코드로 설명 할 수 있습니다.
var x = 1; // 계산량을 줄이기 위해 Math.Pow (2, 53) -10과 같이 초기 값이 더 커질 수 있습니다.
while (x! = x+1) x ++;
// x = 9007199254740992, 즉 2^53
즉, X가 2^53보다 작거나 같을 때 X의 정확도가 손실되지 않도록합니다. x가 2^53보다 클 경우 x의 정확도가 손실 될 수 있습니다. 예를 들어:
x가 2^53 + 1 인 경우 이진 표현은 다음과 같습니다.
1000000000000 ... 001 (중간에 52 0이 있습니다)
이중 정밀 플로팅 포인트 숫자로 보관할 때 :
e = 1; M = 10000..00 (총 52 0, 1은 숨겨진 비트)
분명히 이것은 2^53 스토리지와 동일합니다.
위의 아이디어에 따르면, 2^53 + 2의 경우, 이진은 100000… 0010 (중간에서 51 0)이며 정확하게 저장 될 수 있음을 간략하게 설명 할 수 있습니다.
규칙 : X가 2^53보다 크고 이진 유의 한 숫자의 수가 53 비트보다 클 경우 정확도 손실이 발생합니다. 이것은 기본적으로 소수의 정밀도 손실과 동일합니다.
숨겨진 비트는 참조에 사용할 수 있습니다 : Java Double Type에 대한 튜토리얼.
요약
소수성과 큰 정수의 정확도는 JavaScript에서만 손실되지 않습니다. 엄밀히 말하면, IEEE 754 플로팅 포인트 번호 형식을 사용하여 부동 소수점 유형을 저장하는 모든 프로그래밍 언어 (C/C ++/C#/Java 등)는 정확도 손실 문제가 있습니다. C# 및 Java에서는 정확도 손실을 피하기 위해 해당 처리를 수행하기 위해 소수 및 큰 캡슐화 클래스가 제공됩니다.
참고 : ECMAScript 사양에는 이미 소수점 제안이 있지만 아직 공식적으로 채택되지 않았습니다.
마지막으로 모든 사람을 테스트하십시오.
번호 .max_value + 1 == 숫자 .max_value;
번호 .max_value + 2 == 숫자 .max_value;
...
번호 .max_value + x == 숫자 .max_value;
번호 .max_value + x + 1 == 인피니티;
...
번호 .max_value + 번호 .max_value == 인피니티;
// 질문:
// 1. X의 값은 얼마입니까?
// 2. 인피니티 - 번호 .max_value == x + 1; 진실입니까 아니면 거짓입니까?
JavaScript의 소수성 및 큰 정수의 정확도 손실에 대한 위의 간단한 논의는 내가 공유하는 모든 콘텐츠입니다. 나는 당신이 당신에게 참조를 줄 수 있기를 바랍니다. 그리고 당신이 wulin.com을 더 지원할 수 있기를 바랍니다.