Как решить эту проблему в PHP?

$onethird = 1.0/3;
$fivethirds = 1.0/3+1.0/3+1.0/3+1.0/3+1.0/3;
$half = 1.0/2;
$threehalf = 1.0/2+1.0/2+1.0/2;
var_dump($onethird + $fivethirds == $half + $threehalf);

какие выводы false, но поскольку все мы знаем:5/3+1/3=2=3/2+1/2

Как решить эту проблему?

5
задан Rob 3 January 2010 в 15:25
поделиться

5 ответов

Это одна из проблем IEEE 754 представления чисел с плавающей точкой; представления недостаточно точны для представления всех рациональных чисел.

Способ сделать это - сравнить разницу с очень малым числом для близости, а не равенства:

abs(($onethird + $fivethirds) - ($half + $threehalf)) < 1e-8
5
ответ дан 18 December 2019 в 14:46
поделиться

Это зависит от того, насколько точным должно быть ваше сравнение.
В этом случае следует использовать bccomp() вместо "==".
см. http://php.net/manual/en/language.types.float.php

2
ответ дан 18 December 2019 в 14:46
поделиться
var_dump(abs($onethird + $fivethirds - $half + $threehalf) < 0.00001);

see: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm И ещё: http://docs.sun.com/source/806-3568/ncg_goldberg.html

Это справедливо для всех языков программирования.

Я еще не знаю ни одного языка, где это делается автоматически, когда программисты хотят равенства с плавающей точкой. Кто-то должен придумать оператор new, возможно =~= для равенства float, который автоматически делал бы сравнение diff с epsilon:

if ($float1 =~= $float2) {...

Раздражает то, что каждый год, с тех пор как я закончил в 2000 году, примерно в это время года какой-нибудь новичок будет задавать этот вопрос в какой-нибудь группе новостей, на форуме или в списке рассылки. Только в прошлом месяце я ответил на этот вопрос на сайте comp.lang.tcl. И это не только новички, два месяца назад я должен был объяснить это моему коллеге, который разрабатывал программное обеспечение более 5 лет, спрашивая меня, почему его Perl-код не работает

.
1
ответ дан 18 December 2019 в 14:46
поделиться

Как решить эту проблему?

Какую актуальную проблему вы хотите решить? Ваш код просто показывает, что числа с плавающей точкой имеют ограниченную точность - в этом нет ничего нового.

Для большинства реальных приложений, вход, который все равно не является 100% точным, и результат должен быть точным до пары знаков после запятой. Сравнения равенства просто не нужны большую часть времени. Если нужно, то можно подтасовать его, посмотрев, находится ли результат на некотором предопределенном малом расстоянии от заданного числа.

Если вам нужна десятичная математика с определенной точностью, используйте функции BC Math - но имейте в виду, что они очень медленные, если используются для сложных вычислений.

.
1
ответ дан 18 December 2019 в 14:46
поделиться

Проблема связана с небольшими ошибками, введенными арифметикой с плавающей точкой . Это не специфично для PHP.

Это можно исправить введением небольшого коэффициента "толерантности", т.е. проверкой, что первое значение в сравнении >= второе значение минус допуск и <= второе значение плюс допуск.

4
ответ дан 18 December 2019 в 14:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: