부동소숫점 숫자 (float, double, real number) 다음과 같은 형태로 기술될 수 있다.
<?php
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
정규 표현으로는
LNUM : [0-9]+
DNUM : ([0-9]*[\.]{LNUM} | ({LNUM}[\.][0-9]*)
EXPONENT_DNUM : {+-]?(({LNUM| | {DNUM}) [eE][+-]? {LNUM})
실수 타입의 크기는 시스템마다 다르다.
주의:
부동소수점 정밀도
부동소수점 실수는 한정된 정밀도를 가진다. 비록 시스템마다 다르기는 하지만, PHP는 통상 IEEE 754 배정밀도 포맷을 사용한다. 이는 최대 상대 에러를 1.11e-16 정도 만든다. 또한 0.1이나 0.7과 같이 10을 베이스로 한 실수 표현형은 정확한 2진 베이스의 부동 소수점 숫자로 나타낼 수 없다. 따라서 이들은 해당하는 이진 표현으로 아무런 정밀도 손실 없이 변환될 수 없는 것이다. 이러한 사실로 인해서 다음과 같이 헷갈리는 결과도 만들어 낸다.
floor((0.1+0.7)*10)
위 식의 결과는 0.1 + 0.7 은 0.8 이고, 곱하기 10 하면 8이고, 이에 대해서 floor() 함수를 했으므로, 8이 나와야 할 것 같다. 하지만, 결과는 7이 나온다. 이것은 이것이 내부적으로는 7.99999999999999118... 과 같이 실수로 나왔고, 그에 대해서 floor() 함수를 취했기 때문에 7이 나온 것이다. 따라서, 부동 소수점 숫자의 마지막 자리의 숫자를 마음대로 가정하면 안된다. 또한 부동 소숫점 숫자를 이용해서 동등함의 비교식에 직접 사용해서도 위험하다. 만약에 더 높은 정밀도가 필요하다면, 임의 정밀도 수학 함수들 (arbitrary precision math functions)나 gmp 함수들을 사용할 수 있다.
실수로의 변환
대부분의 경우 숫자로의 변환은 우선은 정수로 변환하려 하고, 그리고 나서 실수로 변환을 시도한다. object를 float로 변환하려고 할 때 notice가 발생한다.
실수의 비교
실수를 이용한 비교 연산은 문제의 소지가 다분하다. 이것은 실수가 내부적으로 표현되는 방식 때문이다. 그렇지만, 실수 값을 비교할 수 있는 방법이 있다.
실수의 동등함을 비교하기 위해서는, 라운딩으로 인한 상대 에러의 상한이 사용된다. 이 값은 machine epsilon으로 알려져 있다. 또는 unit roundoff로 알려져 있다. 이는 연산에 있어서 최소의 가용한 차이를 나타낸다.
<?php
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;
if(abs($a-$b) < $epsilon){
echo "true";
}
?>
위와 같이 두 실수의 차이의 절대값이 최소 변화량보다 작다면 두 실수는 같다고 허용하는 방식인 것이다.
NaN
어떤 숫자 연산은 상수 NaN을 결과로 낼 수 있다. 이 결과는 부동-소수점 계산에 있어서 undefined 또는 unrepresentable 값을 나타낸다. 그 어떤 값 (NaN을 포함해서) 도 NaN과의 비교는 FALSE 결과를 낸다. 따라서 NaN은 다른 값들과 비교되어서는 않된다. 심지어 NaN 그 자신과도 비교해서는 안된다. 오로지 is_nan() 함수를 이용해서 NaN인지 확인만 할 수 있을 뿐이다.
- 번역을 잘못 했는지, 실험해 보니 if(NaN == NaN) 조건문은 참으로 나온다...