Плавающий в int, изменяющий значение простого числа в PHP [дубликат]
На этот вопрос уже есть ответ здесь:
- Математика с плавающей запятой нарушена? 27 ответов
Я использую класс Money, для создания экземпляра которого требуется, чтобы вся валюта находилась в int
. Случилось то, что я наткнулся на определенный номер (я пробовал использовать множество других номеров, и все работает так, как ожидалось) что, когда тип приведен от float
к int
, имеет другое значение.
Я мог бы ожидать этого от числа с очень высокой точностью из-за природы чисел с плавающей запятой в целом, но это не имеет никакого смысла, вот как я могу воспроизвести ошибку...
$value = (float)9.78;
var_dump($value );
$prec = (int)(100);
var_dump($prec);
$value = $value * $prec;
var_dump($value);
var_dump((int)($value));
... который выдает следующий результат...
float(9.78) /* $value as a float */
int(100) /* $prec as an int */
float(978) /* $value * $prec as a float, all going well... */
int(977) /* $value type cast to an int ???????? */
... что, черт возьми, здесь происходит? Почему $value
тип приведен к int
в этом сценарии с другим ценность?
РЕДАКТИРОВАТЬ: Причина, по которой я не принимаю это как дубликат, связана с тем, что ответ, в котором я нуждался, не присутствовал в другом потоке. Вот оно: я должен был подать заявление round()
вот так...
$dec_precision = strlen((string)($prec)-1);
$value = round($value * $prec, $dec_precision);
Надеюсь, это кому-то поможет!
1 answers
PHP использует экспоненциальные представления чисел с плавающей запятой, поэтому он не является точным. Читать документы:
Числа с плавающей запятой имеют ограниченную точность. Хотя это зависит от системы, PHP обычно использует формат двойной точности IEEE 754, который даст максимальную относительную ошибку из-за округления порядка 1.11e-16. Неэлементарные арифметические операции могут давать большие ошибки и, конечно же, распространение ошибок необходимо учитывать, когда несколько операции усложняются.
Кроме того, рациональные числа, которые точно представимы в виде чисел с плавающей запятой в базе 10, например 0.1 или 0.7, не имеют точного представления в виде чисел с плавающей запятой в базе 2, которая используется внутри, независимо от размера мантиссы. Следовательно, они не могут быть преобразованы в свои внутренние двоичные аналоги без небольшой потери точности. Это может привести к запутанным результатам: например, пол((0,1+0,7)*10) обычно будет верните 7 вместо ожидаемых 8, так как внутреннее представление будет примерно таким 7.9999999999999991118....
Обновление 1:
Примечание PHP математические расширения: BCMath и GMP.