2013-09-06 4 views
5

У меня есть ассоциативный массив, значения которого являются поплавками, которые должны быть вероятностями. Таким образом, я суммировать их и требуют, чтобы результат на самом деле 1.Как-то 1 не равно 1 (PHP)

$total = array_sum($array); 
echo '$total = '.$total."\n"; 
if ($total == 1) { 
    die("total is 1"); 
} else { 
    die("total is not 1"); 
} 

Это таинственно выходы:

$total = 1 
total is not 1 

делает var_dump($total) урожаи float(1), и все же даже $total == (float)1 возвращает ложь.

Что происходит?

+2

http://stackoverflow.com/questions/4682889/is-floating-point-ever-ok – thumbmunkeys

ответ

2

поплавков в PHP (и других языках) не являются точными, поэтому (float)1 может быть на самом деле 1.0000000000000 или .99999999999999823477

Посмотреть ответ PHP - Floating Number Precision для получения дополнительной информации

+0

есть ли способ заставить php рассказать мне, какова его фактическая ценность? – Mala

+0

'print (number_format ($ myNumber, 32);' должно позволить вам увидеть с некоторой степенью точности, что это такое, но, насколько я знаю, вы не можете увидеть значение _exact_. – Jordan

+0

whargbl "0.99999999999999988897769753748435" - у меня не было идея var_dump была бы такой же, как – Mala

1

Cast к ИНТ делает

if ((int)$total == 1) 

И он будет работать :)

EDIT: или даже лучше

$total = (int)array_sum($array); 
+1

это, к сожалению, будет бесполезно с тем, что я пытаюсь сделать (см. верхнюю часть вопроса). Если мои ценности были завинчены - что этот код есть, чтобы проверить - и сумма была на самом деле 1.3, она прошла бы тест – Mala

+0

Я вижу, извините, что я неправильно понял ваш вопрос :( – Quillion

3

Значения с плавающей точкой являются по своей природе неточной и очень редко равны друг другу из-за способа их хранения и ошибок округления. Вы должны сравнивать поплавки, видя, являются ли эти два значения «достаточно близкими». То есть, сравнивая абсолютное значение разности между двумя значениями с значительно малым погрешностью (часто называемой «эпсилон»).

Одна такая реализация может быть:

if (abs($total - 1) < 0.000000001) 
    die("total is 1"); 
} else { 
    die("total is not 1"); 
} 

Обратите внимание, что требования только вашего приложения действительно может определить, что безопасный предел погрешности есть и в какой момент номера должны быть закруглены для отображения.


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

Смежные вопросы