PHP의 부동 소수점에 관한 모든 '가짜'는 알아야 합니다. (PHP의 부동 소수점에 대한 모든 '가짜')
PHP는 약한 유형의 언어입니다. 이러한 기능을 사용하려면 PHP 내에서 원활하고 투명한 암시적 유형 변환이 필요합니다. zval을 사용하여 모든 유형의 값을 저장합니다. zval의 구조는 다음과 같습니다(예: 5.2):
struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount; zend_uchar type; /* active type */ zend_uchar is_ref; };
위 구조에서 실제로 값 자체를 저장하는 것은 zvalue_value 공용체입니다.
typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { char *val; int len; } str; HashTable *ht; /* hash table value */ zend_object_value obj; } zvalue_value;
오늘의 주제에서는 두 가지에만 집중합니다. 그중 lval 및 dval 멤버의 경우, 긴 lval의 길이는 컴파일러와 OS의 단어 길이에 따라 32비트일 수도 있고 64비트일 수도 있지만, double dval(이중 정밀도)은 IEEE 754에 의해 지정됩니다. 길이는 고정되어 있으며 64비트여야 합니다.
이 점을 기억하세요. 이로 인해 일부 PHP 코드는 "플랫폼 독립적"이 됩니다. 달리 명시하지 않는 한 다음 논의에서는 long이 64비트라고 가정합니다.
IEEE 인용하지 않겠습니다. 여기서 754의 부동 소수점 계산 방법을 직접 확인할 수 있습니다. 중요한 점은 숨겨진 1개의 유효 비트를 계산하면 총 53비트라는 것입니다. 여기서 매우 흥미로운 질문이 생깁니다. (long이 64비트라고 가정):
long a = x; assert(a == (long)(double)a);
실례합니다. a의 값이 어느 범위 내에 속하는지, 위의 코드가 성공을 주장할 수 있습니까? 기사 끝)
이제 주제로 돌아가 보겠습니다. PHP가 스크립트를 실행하기 전에 먼저 스크립트를 읽고 스크립트를 분석해야 합니다. 다음 스크립트:
<?php $a = 9223372036854775807; //64位有符号数最大值 $b = 9223372036854775808; //最大值+1 var_dump($a); var_dump($b);
Output:
int(9223372036854775807) float(9.22337203685E+18)
즉, 어휘 분석 단계에서 PHP는 리터럴 값이 현재 시스템의 긴 테이블 값 범위를 초과하는지 여부를 판단합니다. 그렇지 않은 경우 lval을 사용하여 저장합니다. IS_LONG, 그렇지 않으면 dval, zval IS_FLOAT로 표시됩니다.
가장 큰 정수 값보다 큰 값을 사용하면 정확도가 떨어질 수 있으므로 주의해야 합니다.
<?php $a = 9223372036854775807; $b = 9223372036854775808; var_dump($a === ($b - 1));
출력이 false입니다.
이제 다음을 계속하세요. 논의를 시작하면서 앞서 언급했듯이 PHP 정수는 32비트일 수도 있고 64비트일 수도 있으므로 64비트에서 정상적으로 실행될 수 있는 일부 코드는 보이지 않는 유형 변환으로 인해 정밀도 손실이 발생할 수 있다고 판단됩니다. 32비트 시스템에서는 코드가 정상적으로 실행될 수 없습니다.
그래서 우리는 이 중요한 값에 주의해야 합니다. 다행히 이 중요한 값은 PHP에 정의되어 있습니다:
<?php echo PHP_INT_MAX; ?>
물론 안전을 위해 다음을 사용해야 합니다. 큰 정수를 저장하고 bcmath와 같은 수학 함수 라이브러리를 사용하여 계산을 수행합니다.
또한, 이 구성은 PHP가 부동 소수점을 출력할지 여부를 결정하는 php.precision입니다.
마지막으로 위에서 제기한 질문, 즉 float로 변환한 후 정밀도가 손실되지 않도록 하기 위한 긴 정수의 최대값이 무엇인지 다시 살펴보겠습니다. ?
예를 들어 정수의 경우 이진 표현이 101이라는 것을 알고 있습니다. 이제 두 비트를 오른쪽으로 이동하여 1.01이 되도록 하고 상위 암시적 유효 비트 1을 버리면 다음과 같은 결과를 얻습니다. double에 저장된 5의 이진 표현 값의 이진 표현은
0/*符号位*/ 10000000001/*指数位*/ 0100000000000000000000000000000000000000000000000000
5이며 가수 부분에 손실 없이 저장됩니다. 이 경우 double에서 long으로 변환할 때 손실이 없습니다. 정밀도
우리는 double이 가수를 표현하기 위해 52비트를 사용한다는 것을 알고 있습니다. 위의 첫 번째 비트 1의 정밀도는 총 53자리입니다. 그러면 긴 정수의 값이 다음보다 작다는 결론을 내릴 수 있습니다.
2^53 - 1 == 9007199254740991; //牢记, 我们现在假设是64bits的long
PHP Tutorial
"위 내용은 PHP 부동 소수점 숫자에 대해 알아야 할 사항의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!