PHP. результат вычитания двух чисел с плавающей запятой

Например…

$aa = 10694994.89;
$bb = 10696193.86;
$ab = $aa - $bb;
// result is:-1198.9699999988 not the -1198,97

Но в этом экзамене:

$cc = 0.89;
$dd = 0.86;
$cd = $cc - $dd;
//Result is: 0.03

Почему разница в примерах? Не хватает точности?

4

Решение

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

Числа с плавающей точкой представлены мантисса (или же мантисса) В диапазоне [1, 2), который масштабируется путем умножения его на степень два. (Это то, что означает «плавающая» в плавающей точке). точность числа определяется количеством цифр в мантисса. точность определяется тем, сколько из этих цифр действительно правильные. Увидеть: Как числа с плавающей запятой хранятся в памяти? Больше подробностей.

Когда ты echo числа с плавающей точкой в ​​PHP, они сначала преобразуются в строку с помощью precision настройка конфигурации, которая по умолчанию равна 14. (В Zend/zend_operators.c)

Чтобы увидеть, что на самом деле происходит, вы должны напечатать числа с большей точностью:

$aa = 10694994.89;
$bb = 10696193.86;
$ab = $aa - $bb;

printf ("\$aa: %.20G\n", $aa);
printf ("\$bb: %.20G\n", $bb);
printf ("\$ab: %.20G\n\n", $ab);

$cc = 0.89;
$dd = 0.86;
$cd = $cc - $dd;

printf ("\$cc: %.20G\n", $cc);
printf ("\$dd: %.20G\n", $dd);
printf ("\$cd: %.20G\n", $cd);

Выход:

$aa: 10694994.890000000596
$bb: 10696193.859999999404
$ab: -1198.9699999988079071

$cc: 0.89000000000000001332
$dd: 0.85999999999999998668
$cd: 0.030000000000000026645

Начальные числа имеют точность от 16 до 17 цифр. Когда вы вычитаете $aa-$bbпервые 4 цифры отменяют друг друга. Результат (с точностью до 16-17 цифр) теперь только точный до 12 цифр. Эта более низкая точность проявляется, когда результаты печатаются с использованием 14-значной точности.

Другое вычитание ($cc-$dd) теряет только одну цифру точности, что не заметно при печати с точностью до 14 цифр.

3

Другие решения

Это должно работать для вас:

(Вы должны округлить свой результат!)

$aa = 10694994.89;
$bb = 10696193.86;
echo $ab = round($aa - $bb, 2);
1