У меня есть следующий код
$amount1 = 7299; $amount2 = 72.9875; $amount2_in_cents = round($amount2, 2) * 100; if ($amount1 != $amount2_in_cents) { echo "Amount $amount1 != $amount2_in_cents\n"; var_dump($amount1); var_dump($amount2_in_cents); } else { echo "Amounts matched"; }
и это результат
Amount 7299 != 7299 int(7299) float(7299)
Теперь я понимаю, что floats и int различны, но, учитывая округление, я ожидал, что два значения будут соответствовать. И я решил это, бросив на int.
Поэтому мой вопрос: почему это сравнение не работает так, как я ожидал (оба значения совпадают)?
Обратите внимание на большое красное предупреждение в Руководстве по PHP !
Никогда не ожидайте ничего, сравнивая поплавки. Результат раунда, даже если точность 0, по-прежнему остается плавающей. В вашем конкретном случае получилось, что результат был немного больше, чем ожидалось, поэтому приведение к int привело к равенству, но для других чисел это могло бы случиться, что оно будет немного меньше ожидаемого, а литье в int не будет округлено он, но обрезает его, поэтому вы не можете использовать кастинг в качестве обходного пути. (В качестве примечания, лучшее решение, чем ваше, будет отличать от строки :), но все же отвратительный вариант.)
Если вам нужно работать с суммой денег, всегда используйте расширение BC Math .
Для округления с помощью BC Math вы можете использовать эту технику:
$x = '211.9452'; $x = bcadd($x, '0.005', 2);
Удачи,
Алинь
использование
round() $float_val = 4.5; $float_val = round($float_val);
сейчас Сравнить
Например, неприятный случай: мы хотим проверить, больше ли наша оценка больше или равна 3,3 из 5, находясь в цикле. (Это все странный пример, чтобы показать «недостаток»)
$a="3.3"; for($i=0; $i<5 ; $i=$i+0.15){ echo "\nTesting if $i>=$a\n"; var_dump($i,$a); if($i>=$a){ echo "$i>=$a is TRUE\n"; }else{ echo "$i>=$a is FALSE\n"; } }
Теперь выход будет следующим:
Testing if 0>=3.3 int(0) string(3) "3.3" 0>=3.3 is FALSE Testing if 0.15>=3.3 float(0.15) string(3) "3.3" 0.15>=3.3 is FALSE Testing if 0.3>=3.3 float(0.3) string(3) "3.3" 0.3>=3.3 is FALSE Testing if 0.45>=3.3 float(0.45) string(3) "3.3" 0.45>=3.3 is FALSE Testing if 0.6>=3.3 float(0.6) string(3) "3.3" 0.6>=3.3 is FALSE Testing if 0.75>=3.3 float(0.75) string(3) "3.3" 0.75>=3.3 is FALSE Testing if 0.9>=3.3 float(0.9) string(3) "3.3" 0.9>=3.3 is FALSE Testing if 1.05>=3.3 float(1.05) string(3) "3.3" 1.05>=3.3 is FALSE Testing if 1.2>=3.3 float(1.2) string(3) "3.3" 1.2>=3.3 is FALSE Testing if 1.35>=3.3 float(1.35) string(3) "3.3" 1.35>=3.3 is FALSE Testing if 1.5>=3.3 float(1.5) string(3) "3.3" 1.5>=3.3 is FALSE Testing if 1.65>=3.3 float(1.65) string(3) "3.3" 1.65>=3.3 is FALSE Testing if 1.8>=3.3 float(1.8) string(3) "3.3" 1.8>=3.3 is FALSE Testing if 1.95>=3.3 float(1.95) string(3) "3.3" 1.95>=3.3 is FALSE Testing if 2.1>=3.3 float(2.1) string(3) "3.3" 2.1>=3.3 is FALSE Testing if 2.25>=3.3 float(2.25) string(3) "3.3" 2.25>=3.3 is FALSE Testing if 2.4>=3.3 float(2.4) string(3) "3.3" 2.4>=3.3 is FALSE Testing if 2.55>=3.3 float(2.55) string(3) "3.3" 2.55>=3.3 is FALSE Testing if 2.7>=3.3 float(2.7) string(3) "3.3" 2.7>=3.3 is FALSE Testing if 2.85>=3.3 float(2.85) string(3) "3.3" 2.85>=3.3 is FALSE Testing if 3>=3.3 float(3) string(3) "3.3" 3>=3.3 is FALSE Testing if 3.15>=3.3 float(3.15) string(3) "3.3" 3.15>=3.3 is FALSE Testing if 3.3>=3.3 float(3.3) string(3) "3.3" 3.3>=3.3 is FALSE Testing if 3.45>=3.3 float(3.45) string(3) "3.3" 3.45>=3.3 is TRUE Testing if 3.6>=3.3 float(3.6) string(3) "3.3" 3.6>=3.3 is TRUE Testing if 3.75>=3.3 float(3.75) string(3) "3.3" 3.75>=3.3 is TRUE Testing if 3.9>=3.3 float(3.9) string(3) "3.3" 3.9>=3.3 is TRUE Testing if 4.05>=3.3 float(4.05) string(3) "3.3" 4.05>=3.3 is TRUE Testing if 4.2>=3.3 float(4.2) string(3) "3.3" 4.2>=3.3 is TRUE Testing if 4.35>=3.3 float(4.35) string(3) "3.3" 4.35>=3.3 is TRUE Testing if 4.5>=3.3 float(4.5) string(3) "3.3" 4.5>=3.3 is TRUE Testing if 4.65>=3.3 float(4.65) string(3) "3.3" 4.65>=3.3 is TRUE Testing if 4.8>=3.3 float(4.8) string(3) "3.3" 4.8>=3.3 is TRUE Testing if 4.95>=3.3 float(4.95) string(3) "3.3" 4.95>=3.3 is TRUE
И отвратительная часть:
Testing if 3.3>=3.3 float(3.3) string(3) "3.3" 3.3>=3.3 is FALSE
3.3 больше или равно 3.3, но php вещи нет! Не имеет никакого смысла
Теперь, если вы положили ini_set('precision', 18);
перед кодом вы можете видеть, что оценка на самом деле была:
Testing if 3.29999999999999893>=3.3 float(3.29999999999999893) string(3) "3.3" 3.29999999999999893>=3.3 is FALSE
Таким образом, $ i = $ i + = 0,15 неявно преобразует $ i в float , что вызовет эту проблему.
Для этого случая $ i + = 0,15 следует изменить на $ i = number_format ($ i + = 0,15, 2)