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

Раздел: PHP программирование -> Числа в PHP

Основы работы с числами с плавающей точкой в PHP

Наиболее эффективное решение для избежания ошибок точности при сравнении чисел с плавающей точкой - использование эпсилон (допустимой погрешности). Прямое сравнение через == или === приводит к неожиданным результатам из-за внутреннего представления IEEE 754. Вместо этого следует проверять, разница между числами меньше заданного порога.


$a = 0.1 + 0.2;
$b = 0.3;

// Неправильно:
if ($a == $b) {
    // никогда не выполнится
}

// Правильно:
$epsilon = 0.00001;
if (abs($a - $b) < $epsilon) {
    echo "Числа равны в пределах эпсилон";
}

Php случайное число (генерация случайного числа в php)

Цель - надёжное сравнение float-значений в любых расчётах. Случаи использования: финансовые вычисления, научные расчёты, проверка результатов математических операций.

Типичные проблемы:

  • Значение NaN не равно самому себе - проверка через is_nan().
  • Бесконечность INF - проверка через is_infinite().
  • Потеря точности при сложении/вычитании чисел разного порядка (например, 1e20 + 1).

Решение - выбирать эпсилон, соразмерный величине чисел. Для денежных сумм достаточно 0.001, для научных вычислений может потребоваться 1e-10.

Как избежать ошибок точности при работе с деньгами?

Цель: работа с денежными суммами без потери точности. Случай использования: интернет-магазины, бухгалтерия. Вместо float рекомендуется хранить сумму в копейках (целое число) и оперировать только целыми.


// Хранение 10.50 руб как 1050 копеек
$priceInKopeks = 1050;
$quantity = 3;
$totalKopeks = $priceInKopeks * $quantity; // 3150
$totalRubles = $totalKopeks / 100; // 31.5 (но лучше не делить до вывода)

количество чисел php (количество чисел в php)

Проблемы: деление даёт дробный остаток, требуется правильное округление при распределении сумм. Рекомендуется округлять до целых копеек с помощью round().

Ошибка: умножение/деление с плавающей точкой после приведения обратно может вернуть неточность. Лучше держать всё в целых числах до финального вывода.

Как выполнять вычисления с высокой точностью?

Цель: произвольная точность (до 100 знаков и более). Случай использования: научные расчёты, криптография, статистика. Решение - расширение bcmath (Binary Calculator).


$a = '0.1';
$b = '0.2';
$result = bcadd($a, $b, 10); // третий параметр - количество знаков после запятой
echo $result; // 0.3

массив чисел php (массив чисел в php)

Проблемы: расширение не входит в ядро PHP (требуется установка), работает медленнее float. Все операнды должны быть строками.

Ошибка: передача float в bcmath может привести к потере точности. Всегда передавайте числа как строки.

Как вывести число с плавающей точкой с нужным количеством знаков?

Цель: форматирование вывода для пользователя. Случай использования: отображение цен, процентов. Функция number_format() позволяет задать количество знаков, разделитель целой и дробной части, разделитель тысяч.


$price = 1234.5678;
echo number_format($price, 2, '.', ''); // 1234.57 (округление)
echo number_format($price, 2, ',', ' '); // 1 234,57

Php получить число (получение числа в php)

Проблемы: функция выполняет округление по правилам PHP_ROUND_HALF_UP. При необходимости другого округления нужно предварительно применить round() с нужным режимом.

Ошибка: неверная локализация - если сервер расположен в другой стране, разделители могут отличаться. Рекомендуется явно задавать разделители.

Как округлить число по различным правилам?

Цель: математическое округление, округление до ближайшего чётного, вниз, вверх. Случай использования: статистика, округление налогов. Функция round() поддерживает режимы: PHP_ROUND_HALF_UP (по умолчанию), PHP_ROUND_HALF_DOWN, PHP_ROUND_HALF_EVEN, PHP_ROUND_HALF_ODD.


// Округление 1.5 до целого
var_dump(round(1.5, 0, PHP_ROUND_HALF_UP));   // 2
var_dump(round(1.5, 0, PHP_ROUND_HALF_DOWN)); // 1
var_dump(round(1.5, 0, PHP_ROUND_HALF_EVEN)); // 2 (т.к. 2 чётное)
var_dump(round(1.5, 0, PHP_ROUND_HALF_ODD));  // 1 (т.к. 1 нечётное)

Проблемы: режимы применяются только для дробной части 0.5. Для других значений округление идёт по стандартным правилам.

Ошибка: забыли указать режим - получите неожиданный результат (например, при банковском округлении).

- Php целое число (проверка целого числа в php)
- Php большие числа (работа с большими числами в php)
- Php сумма чисел (сумма чисел в php)

Расширенные примеры работы с float

Ниже приведены дополнительные сценарии, демонстрирующие особенности чисел с плавающей точкой в PHP.

Пример 1. Сложение 0.1 и 0.2 с детальным анализом

Классический пример неточности.

Пример

$a = 0.1;
$b = 0.2;
$c = $a + $b;
echo "Результат сложения: " . $c . "\n";
echo "Сравнение с 0.3: " . ($c == 0.3 ? 'true' : 'false') . "\n";
echo "Разница: " . ($c - 0.3) . "\n";

// Исправление через эпсилон
$eps = 1e-10;
if (abs($c - 0.3) < $eps) {
    echo "Корректное сравнение: числа равны\n";
}
Результат сложения: 0.3
Сравнение с 0.3: false
Разница: 5.5511151231258E-17
Корректное сравнение: числа равны

Пример 2. Использование bcmath для сложения с 30 знаками

Пример

// Строки, а не float
$a = '0.12345678901234567890';
$b = '0.98765432109876543210';
$result = bcadd($a, $b, 30);
echo "Сумма: $result\n";
Сумма: 1.11111111011111111100

Пример 3. Потеря точности при работе с очень большими и малыми числами

Пример

$big = 1e20;
$small = 1;
$sum = $big + $small;
echo "1e20 + 1 = " . $sum . "\n";
echo "Разница с 1e20: " . ($sum - $big) . " (ожидалось 1)\n";
1e20 + 1 = 1.0E+20
Разница с 1e20: 0 (ожидалось 1)

Пояснение: мантисса не может представить 1 при таком большом порядке, поэтому прибавление 1 не меняет числа.

Пример 4. Преобразование строки в float и обратная потеря

Пример

$str = '12.34567890123456789';
$float = (float) $str;
echo "Исходная строка: $str\n";
echo "Преобразованный float: " . var_export($float, true) . "\n";
echo "Обратно в строку: " . (string) $float . "\n";
Исходная строка: 12.34567890123456789
Преобразованный float: 12.345678901235
Обратно в строку: 12.345678901235

Видна потеря точности - последние цифры заменены.

Пример 5. Округление с различными режимами для дробной части 0.5

Пример

$number = [1.5, 2.5, 3.5, 4.5];
foreach ($number as $n) {
    echo "Число: $n -> ";
    echo "UP: " . round($n, 0, PHP_ROUND_HALF_UP) . " ";
    echo "DOWN: " . round($n, 0, PHP_ROUND_HALF_DOWN) . " ";
    echo "EVEN: " . round($n, 0, PHP_ROUND_HALF_EVEN) . " ";
    echo "ODD: " . round($n, 0, PHP_ROUND_HALF_ODD) . "\n";
}
Число: 1.5 -> UP: 2 DOWN: 1 EVEN: 2 ODD: 1
Число: 2.5 -> UP: 3 DOWN: 2 EVEN: 2 ODD: 3
Число: 3.5 -> UP: 4 DOWN: 3 EVEN: 4 ODD: 3
Число: 4.5 -> UP: 5 DOWN: 4 EVEN: 4 ODD: 5

Пример 6. Форматирование цены с числовыми разделителями и без потери точности

Пример

$price = 1234567.89123;
echo "Исходное: $price\n";
echo "2 знака: " . number_format($price, 2, '.', ',') . "\n";
echo "4 знака с пробелом: " . number_format($price, 4, '.', ' ') . "\n";

// Округление до 2 знаков + форматирование
$rounded = round($price, 2);
echo "Округлённое: " . number_format($rounded, 2, '.', ',') . "\n";
Исходное: 1234567.89123
2 знака: 1,234,567.89
4 знака с пробелом: 1 234 567.8912
Округлённое: 1,234,567.89

Пример 7. Тригонометрические функции и погрешность

Пример

$sin60 = sin(deg2rad(60));
echo "sin(60°) = " . $sin60 . "\n";
echo "Ожидается √3/2 ≈ " . (sqrt(3)/2) . "\n";
echo "Разница: " . abs($sin60 - sqrt(3)/2) . "\n";
sin(60°) = 0.86602540378444
Ожидается √3/2 ≈ 0.86602540378444
Разница: 1.1102230246252E-16

Погрешность в пределах машинного эпсилон.

Число с плавающей точкой в PHP - comments

En
Php число с точкой (php)