PHP: float/double - числo с плавающей точкой

В этой главе:

  • Точность чисел с плавающей точкой
  • Преобразование в число с плавающей точкой
  • Сравнение чисел с плавающей точкой
  • Значение NaN

Числа с плавающей точкой, могут быть определены следующим образом:

1
2
3
4
5
6
7
<?php
 
  $a = 1.234;
  $b = 1.2e3;
  $c = 7E-10;
 
?>

Размер числа с плавающей точкой зависит от платформы, хотя максимум, как правило составляет ~1.8e308 с точностью около 14 десятичных цифр.

Точность чисел с плавающей точкой

Числа с плавающей точкой имеют ограниченную точность. Хотя это зависит от операционной системы, в PHP обычно используется формат двойной точности IEEE 754, дающий максимальную относительную ошибку округления порядка 1.11e-16. Неэлементарные арифметические операции могут давать большие ошибки, и, разумеется, необходимо принимать во внимание распространение ошибок при совместном использовании нескольких операций.

Кроме того, рациональные числа, которые могут быть точно представлены в виде чисел с плавающей точкой с основанием 10, например, 0.1 или 0.7, не имеют точного внутреннего представления в качестве чисел с плавающей точкой с основанием 2, вне зависимости от размера мантиссы. Поэтому они и не могут быть преобразованы в их внутреннюю двоичную форму без небольшой потери точности. Это может привести к неожиданным результатам: например, floor((0.1+0.7)*10) скорее всего вернет 7 вместо ожидаемого 8, так как результат внутреннего представления будет чем-то вроде 7.9999999999999991118....

Так что никогда не доверяйте точности чисел с плавающей точкой до последней цифры, и не проверяйте напрямую их равенство. Если вам действительно необходима высокая точность, используйте математические функции произвольной точности и gmp-функции.

Преобразование в число с плавающей точкой

О преобразовании строк в числа с плавающей написано в разделе "Преобразование строк в числа". Для значений других типов, преобразование будет сначала осуществлено в тип integer, а затем в число с плавающей точкой. При преобразовании объекта к числу с плавающей точкой выводится замечание об ошибке.

Для явного преобразования в вещественное число (float), используйте явное приведение (float), (double) или (real):

1
2
3
4
5
6
7
<?php
 
  var_dump((float) 5);
  var_dump((double) 10);
  var_dump((real) 15);
 
?>

Сравнение чисел с плавающей точкой

Проверять числа с плавающей точкой на равенство проблематично из-за их внутреннего представления. Тем не менее, существуют способы для их сравнения, которые работают несмотря на все эти ограничения. Для сравнения чисел с плавающей точкой используется верхняя граница относительной ошибки при округлении. Эта величина называется машинной эпсилон или единица округления(unit roundoff) и представляет собой самую маленькую допустимую разницу при расчетах:

1
2
3
4
5
6
7
8
9
10
11
<?php
 
  $a = 1.23456789;
  $b = 1.23456780;
  $epsilon = 0.00001;
 
  if(abs($a-$b) < $epsilon) {
    echo "true";
  }
 
?>

Значение NaN

Если в сообщении об ошибке когда-либо появляется сокращение NaN (или NAN), это означает, что какая-то используемая математическая функция вышла за пределы допустимого диапазона значений или не смогла обработать свои входные данные. Значение NaN является сокращением от "Not a Number" (нечисловое значение) и означает неопределенное или непредставимое значение в операциях с плавающей точкой. Любое строгое или нестрогое сравнение данного значения с другим значением, включая его самого, возвратит FALSE. Значение NAN не следует сравнивать с другими значениями, включая его самого. Вместо этого, для определения его наличия необходимо использовать функцию is_nan().

Ниже в примере показано, что происходит при попытке получить арккосинус числа 8, притом что значение арккосинуса определено только в случае применения его к числам в пределах от -1.0 до 1.0:

1
2
3
4
5
6
7
8
9
<?php
 
  // Недопустимое вычисление, возвращает
  // значение "не число" (NaN)
  $nan = acos(8);
 
  var_dump($nan, is_nan($nan));
 
?>