Почему `intval (19.9 * 100)` равно `1989`?

Мальчик, этот действительно странный. Я ожидаю, что следующий код будет напечатан в 1990 году, но он печатает 1989 год!

$val = '$19.9';

$val = preg_replace('/[^\d.]/','',$val);
$val = intval($val * 100);

echo $val;

Почему это происходит?

Изменить: и этот код:

$val = '$19.9';
$val = preg_replace('/[^\d.]/','',$val);
echo $val . "<br>";
$val = $val * 100;
echo $val . "<br>";
$val = intval($val);
echo $val;

Печать

19.9
1990
1989

Почему intval(1990) равно 1989???

Ответ 1

Это точная проблема, присущая номерам с плавающей запятой в PHP и множеству других языков. Этот отчет об ошибке немного обсуждается в контексте кастинга как int:

http://bugs.php.net/bug.php?id=33731

Попробуйте round($val * 100).

Ответ 3

Почему intval (1990) равен 1989???

Потому что вы не принимаете intval(1990). Вы принимаете intval($val * 100), где $val - это число, близкое к нему, но немного меньшее, чем 19.9.

Прочитайте Руководство по плавающей запятой, чтобы понять, почему это так.

Как исправить это: никогда не используйте значения с плавающей запятой за деньги. В PHP вы должны использовать BCMath.

Ответ 4

$val - число с плавающей запятой - результат "19.9" * 100. Номера с плавающей точкой не являются точными на 100% на любом языке (это по дизайну). Если вам нужна 100-процентная десятичная точность для значений доллара, вы должны использовать целые числа и выполнять все вычисления с использованием центов (например, "$19.90" должно быть 1990).