Я пишу serialize()
парсер / валидатор, и я столкнулся с этим (несколько неожиданное поведение):
$float = 875.6745;
echo "serialize({$float}) === " . serialize($float) . "\n";
echo "(float) \"875.67449999999997\" === " . ((float) "875.67449999999997") . "\n";
Выход:
serialize (875.6745) === d: 875.67449999999997;
(float) «875.67449999999997» === 875.6745
Когда я сериализую число с плавающей запятой, сохраненное значение на самом деле не совпадает с вводом, однако, когда сериализованная строкаfloat
ed, значение снова совпадает …
Должен ли я быть обеспокоен?
Короткий ответ: вам почти наверняка не нужно беспокоиться.
Длинный ответ: PHP просто печатает достаточно цифр, чтобы гарантировать, что он может правильно прочитать число точно.
Нет числа с плавающей запятой 875.6745. Когда вы вводите число, оно преобразуется в двоичный код IEEE754 (a.k.a C double
на большинстве компьютеров сегодня) формат, который округляет его до:
875,6744999999999663486960344016551971435546875
Когда вы сериализуете его, он не печатает этот номер (и не нуждается): вместо этого он просто сохраняет 17 цифр, этого достаточно, чтобы обеспечить возможность точного считывания значения.
Это преобразование должно быть согласованным для большинства современных аппаратных средств, и вам не нужно беспокоиться о 32-х и 64-битных платформах: это абсолютно не имеет отношения к числам с плавающей запятой (у нас были «родные» 64-битные операции с 16-битными 8086).
(Технически, PHP говорит, что размер поплавка зависит от платформы, но если вы не имеете дело с 30 лет оборудования, вам не нужно беспокоиться).
Других решений пока нет …