Числа с плавающей запятой
Числа с плавающей запятой (также известные как "float", "double" или "real") могут быть определены следующими синтаксисами:
<?php
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
$d = 1_234.567; // начиная с PHP 7.4.0
?>
Формально, начиная с PHP 7.4.0 (ранее подчеркивание не разрешалось):
LNUM [0-9]+(_[0-9]+)* DNUM ([0-9]*(_[0-9]+)*[\.]{LNUM}) | ({LNUM}[\.][0-9]*(_[0-9]+)*) EXPONENT_DNUM (({LNUM} | {DNUM}) [eE][+-]? {LNUM})
Размер числа с плавающей запятой зависит от платформы, хотя максимум, как правило, составляет 1.8e308 с точностью около 14 десятичных цифр (64-битный формат IEEE).
Точность чисел с плавающей запятой
Числа с плавающей запятой имеют ограниченную точность. Хотя это зависит от операционной системы, в PHP обычно используется формат двойной точности IEEE 754, дающий максимальную относительную ошибку округления порядка 1.11e-16. Неэлементарные арифметические операции могут давать большие ошибки, и, разумеется, необходимо принимать во внимание распространение ошибок при совместном использовании нескольких операций.
Кроме того, рациональные числа, которые могут быть точно представлены
в виде чисел с плавающей запятой с основанием 10, например,
0.1
или 0.7
, не имеют
точного внутреннего представления в качестве чисел с плавающей запятой
с основанием 2, вне зависимости от размера мантиссы.
Поэтому они и не могут быть преобразованы в их внутреннюю двоичную форму
без небольшой потери точности. Это может привести к неожиданным результатам:
например, floor((0.1+0.7)*10)
скорее всего вернет
7
вместо ожидаемого 8
, так как
результат внутреннего представления будет чем-то вроде
7.9999999999999991118...
.
Так что никогда не доверяйте точности чисел с плавающей запятой до последней цифры и не проверяйте напрямую их равенство. Если вам действительно необходима высокая точность, используйте математические функции произвольной точности и gmp-функции.
"Простое" объяснение можно найти в » руководстве по числам с плавающей запятой, которое также называется "Why don’t my numbers add up?" ("Почему мои числа не складываются?")
Преобразование в число с плавающей запятой
Из строк
Если строка
содержащая число
или ведущая числовая, тогда она будет преобразована в соответствующее целочисленное значение,
в противном случае она преобразуется в ноль
(0
).
Из других типов
Для значений других типов преобразование выполняется путем преобразования значения сначала в целое число (int), а затем в число с плавающей запятой ( float ). Смотрите Преобразование в целое число для получения дополнительной информации.
Замечание:
Поскольку определенные типы имеют неопределенное поведение при преобразовании в целое число (int), то же самое происходит и при преобразовании в число с плавающей запятой (float).
Сравнение чисел с плавающей точкой
Как указано выше, проверять числа с плавающей запятой на равенство проблематично из-за их внутреннего представления. Тем не менее, существуют способы для их сравнения, которые работают несмотря на все эти ограничения.
Для сравнения чисел с плавающей запятой используется верхняя граница относительной ошибки при округлении. Эта величина называется машинной эпсилон или единицей округления (unit roundoff) и представляет собой самую маленькую допустимую разницу при расчетах.
$a и $b равны до 5-ти знаков после запятой.
<?php
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;
if (abs($a - $b) < $epsilon) {
echo "true";
}
?>
NaN
Некоторые числовые операции могут возвращать значение, представляемое
константой NAN
. Данный результат означает неопределенное
или непредставимое значение в операциях с плавающей точкой. Любое строгое
или нестрогое сравнение данного значения с другим значением, кроме true
, включая его
самого, возвратит false
.
Так как NAN
представляет собой неограниченное количество
различных значений, то NAN
не следует сравнивать с
другими значениями, включая ее саму. Вместо этого, для определения ее наличия
необходимо использовать функцию is_nan().