C언어와 C#언어에서는 부동소수점형의 데이터를 단정밀도형(float), 이중정밀도형(double)을 사용하여 저장하며, double형 데이터는 64비트를 차지한다고 선언하고 있습니다. 변수 float f= 2.25f일 때 메모리는 어떻게 할당됩니까? 무작위로 할당하면 세상이 혼란스럽지 않을까요? 사실 float와 double은 모두 IEEE R32.24를 따르고, double은 R64.53을 따릅니다.
단정밀도이든 배정밀도이든 저장은 세 부분으로 나뉩니다.
부호 비트(Sign): 0은 양수를 나타내고 1은 음수를 나타냅니다. 시프트 저장 사용
Mantissa(Mantissa): Mantissa 부분
이 글은 주로 PHP 부동 소수점 수 정확도 문제에 대한 요약을 소개합니다. 이 글은 세 가지 다른 문단을 사용하여 PHP 부동 소수점 수 정확도 손실 문제에 중점을 두고 있습니다. 이 문제의 원인과 해결 방법은 도움이 필요한 친구들이 참고할 수 있습니다
1. PHP 부동 소수점 정밀도 손실 문제먼저 다음 코드를 살펴보세요.
코드는 다음과 같습니다.
$f = 0.57; echo intval($f * 100); //56
결과는 다음과 같습니다. 조금 놀랍습니다. PHP는 IEEE 754 배정밀도를 따릅니다.
64비트 배정밀도의 부동 소수점 숫자는 1개의 부호 비트(E), 11개의 지수 비트(Q) 및 52개의 가수(M)로 표시됩니다. 비트(총 64비트).
부호 비트: 가장 높은 비트는 데이터의 부호를 나타내며, 0은 양수, 1은 음수를 나타냅니다.지수 비트: 2를 밑으로 하는 데이터의 거듭제곱을 나타내며, 지수는 오프셋 코드로 표현됩니다.
가수: 데이터의 소수점 이하 유효 숫자를 나타냅니다.
소수점을 어떻게 표현하는지 살펴보겠습니다. 이진수:
2를 곱하고 반올림하여 순서대로 정렬합니다. 즉, 소수 부분에 2를 곱한 다음
정수 부분을 취하고, 계속해서 나머지 소수 부분에 2를 곱한 다음 정수 부분을 취합니다. , 그리고 나머지 소수부를 다시 2를 곱하여 소수부를 취할 때까지 하게 되는데 0.57과 같이 계속 이렇게 소수부를 곱하면 소수부는 0이 될 수 없습니다. 유효숫자의 소수부는 2진수로 표현하면 무한대입니다. 0.57의 이진 표현은 기본적으로(52비트): 0010001111010111000010100011110101110000101000111101
만 52비트인 경우 0.57 => 0.5699999999999999 5
위에서 예상치 못한 결과를 보는 것은 어렵지 않습니다.
2. PHP 부동 소수점 숫자의 정확성 문제먼저 질문을 살펴보겠습니다.
코드는 다음과 같습니다.$f = 0.58;
var_dump(intval($f * 100)); //为啥输出57
많은 학생들이 이런 질문을 했을 거라 믿습니다.
특정 원리에 대해서는 "Brother Bird"의 기사에서 자세한 설명을 읽을 수 있습니다.
FAQPHP 부동 소수점 숫자에 대한 답변 그렇다면 이 문제를 피하는 방법은 무엇일까요?
여러 가지 방법이 있습니다. 다음은 두 가지입니다.substr(sprintf("%.10f", ($a/ $b)), 0, -7);
2.round(반올림됩니다.)
코드는 다음과 같습니다.
round($a/$b, 3);
또는 더 좋은 방법이 있다면 메시지를 남겨서 알려주실 수도 있습니다.
3. PHP 부동 소수점 숫자에 대한 일반적인 질문에 대한 답변PHP 부동 소수점 숫자에 관해 이전에 다음과 같은 기사를 쓴 적이 있습니다. PHP의 부동 소수점에 관한 모든 '가짜'
그러나 나는 한 가지를 놓쳤습니다.
코드는 다음과 같습니다.
<?php $f = 0.58; var_dump(intval($f * 100)); //为啥输出57 ?>
출력이 57인 이유는 무엇인가요? 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비트)입니다 1100001010001111 0101110000101000111101
그리고 계산하면 둘의 이진수
코드 복사
0.58 -> 0.57999999999999996 0.57 -> 0.569999999999999950.58 * 100의 특정 부동 소수점 곱셈에 대해서는 자세히 고려하지 않습니다. (부동소수점)을 보면 암산으로 막연하게 살펴보게 되는데... 0.58 * 100 = 57.999999999
그러면 자연스럽게 57이 되겠죠…
이 문제의 핵심은 다음과 같습니다. "유한해 보이는 소수는 컴퓨터의 이진수 표현에서 실제로는 무한합니다."
위 내용은 PHP 부동 소수점 정밀도에 관한 질문의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!