Публикации
Публикации  »  PHP

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

Иногда, когда работаешь с дробными числами в php можно получить неожиданные результаты и складывается впечатление, что php неправильно округляет в большую или меньшую сторону числа с плавающей точкой. Вот пример некорректного округления в меньшую сторону функцией floor:

$a = 0.1;
$b = 0.7;
echo floor(($a + $b) * 10); // выведет 7 вместо ожидаемого 8

Или вот еще один пример неправильного округления функцией ceil:

$a = 33.7;
echo ceil($a * 100); // выводит 3371 вместо ожидаемого 3370

На самом деле все дело не в округлении, а в том, как php хранит в памяти числа с плавающей точкой. Казалось бы вполне точное число, например, 0.8 на самом деле в памяти может быть числом 0.7999999999...

Есть 2 варианта как можно выйти из положения.

1-й способ

Преобразовывать числа в строку и выполнять "вручную" действия деления, умножения, сложения, вычитания и т.д. Не буду останавливаться на этом варианте, т.к. написание такой программы будет трудоемко и на мой взгляд малоэффективно, а вот второй способ гораздо лучше и правильнее.

2-й способ

Использовать функции BC Math, которые поддерживают числа любого размера и точности. Приведу их перечень:

  • bcadd — Сложить 2 числа произвольной точности
  • bccomp — Сравнение двух чисел произвольной точности
  • bcdiv — Операция деления для чисел произвольной точности
  • bcmod — Получает остаток от деления чисел с произвольной точностью
  • bcmul — Умножение двух чисел с произвольной точностью
  • bcpow — Возведение в степень чисел с произвольной точностью
  • bcpowmod — Возводит одно число в степень другого и возвращает остаток от деления результата на третье число
  • bcscale — Задает количество чисел после десятичной точки по умолчанию для всех bc math функций.
  • bcsqrt — Извлекает квадратный корень из числа с заданной точностью
  • bcsub — Вычитает одно число из другого с заданной точностью

Подробнее с этими функциями можно познакомиться на php.net

Категория: PHP

Комментарии к статье:

Пока комментариев нет, ваш будет первым ;)

Добавить комментарий: