1. PHP 부동 소수점 정밀도 손실 문제
먼저 다음 코드를 살펴보세요.
결과가 다소 놀라울 수도 있습니다. PHP는 IEEE 754 배정밀도 를 따릅니다.
64비트 배정밀도의 부동 소수점 수는 1개의 부호 비트(E), 11개의 지수 비트(Q) 및 52비트 가수(M)(총 64비트)로 표현됩니다.
부호 비트: 가장 높은 비트는 데이터의 부호를 나타내고, 0은 양수, 1은 음수를 나타냅니다.
지수 비트 : 2진수로 거듭제곱한 데이터를 나타내며, 지수는 오프셋 코드로 표현됩니다
가수 : 데이터의 소수점 이하 유효숫자를 나타냅니다.
십진수를 이진수로 표현하는 방법을 살펴보겠습니다.
2를 곱하고 반올림하여 순서대로 배열합니다. 즉, 소수부에 2를 곱한 다음 정수부를 취하고, 계속해서 나머지 소수부에 2를 곱하고, 그 다음 정수부를 취하고, 나머지 소수부를 곱합니다. 2로 나눠서 계속해서 소수점까지 취하는데, 이렇게 0.57과 같은 소수점을 곱하면 소수부는 0이 될 수 없습니다. 유효숫자의 소수점 표현은 이진수로 무한대입니다.
0.57의 이진 표현은 기본적으로(52비트)입니다: 0010001111010111000010100011110101110000101000111101
52비트만 있으면 0.57 => 0.56999999999999995
위에서 예상치 못한 결과를 보는 것은 어렵지 않습니다.
2. PHP 부동 소수점 수의 정밀도 문제
먼저 질문을 살펴보겠습니다.
많은 학생들이 이런 질문을 했을 거라 생각합니다.
구체적인 원리에 대해서는 "Brother Bird"의 기사에서 자세한 설명을 읽을 수 있습니다. PHP 부동 소수점 숫자에 대한 일반적인 질문에 대한 답변
그렇다면 이 문제를 피하는 방법은 무엇일까요?
여러 가지 방법이 있습니다. 다음은 두 가지입니다.
1. 스프린트
3. PHP 부동 소수점 숫자에 대한 일반적인 질문에 대한 답변
PHP의 부동 소수점 숫자에 관해 이전에 다음 기사를 쓴 적이 있습니다. PHP의 부동 소수점에 대한 모든 '가짜'(PHP의 부동 소수점에 대한 모든 '가짜')
그런데 제가 놓친 것이 하나 있는데, 바로 이 일반적인 질문에 대한 답입니다.
bugs.php.net에 자주 질문하는 것은 물론, 비슷한 질문을 하는 분들이 많아서 많은 학생들이 이런 질문을 했을 거라 믿습니다...
이 이유를 이해하려면 먼저 부동 소수점 숫자의 표현을 알아야 합니다(IEEE 754).
예를 들어 64비트 길이(이중 정밀도)를 사용하는 부동 소수점 숫자는 1개의 부호 비트(E), 11개의 지수 비트(Q) 및 52비트 가수(M)로 표시됩니다(총 64비트).
부호 비트: 가장 높은 비트는 데이터의 부호를 나타내며, 0은 양수, 1은 음수를 나타냅니다.
지수 비트 : 2진수로 거듭제곱한 데이터를 나타내며, 지수는 오프셋 코드로 표현됩니다.
가수 : 데이터의 소수점 이하 유효숫자를 나타냅니다.
여기서 핵심은 십진수를 이진수로 표현하는 것입니다. 십진수를 이진수로 표현하는 방법은 Baidu에서 검색할 수 있습니다. 여기서는 이진수에 대해 자세히 설명하지 않겠습니다. 표현, 0.58은 무한합니다. 긴 값(아래 숫자는 암시적 1을 생략함)..
0.58의 이진 표현은 기본적으로(52비트)입니다: 0010100011110101110000101000111101011100001010001111
0.57의 이진 표현은 기본적으로(52비트)입니다: 0010001111010111000010100011110101110000101000111101
이 52비트를 통해서만 계산할 경우 둘의 이진수는 다음과 같습니다.
그럼 인테이크하면 자연스럽게 57이 되겠죠…
이 문제의 핵심은 "유한해 보이는 소수는 컴퓨터의 이진 표현에서 실제로는 무한하다"는 점임을 알 수 있습니다.
이것이 PHP 버그라고 생각하지 마세요. 이것이 바로...