I have the following code
$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";
}
and this is the output
Amount 7299 != 7299
int(7299)
float(7299)
Now I realise that floats and int are different, but given the rounding i would have expected the two values to match. And I have solved it by casting to int.
So my question is why does this comparison not work 开发者_高级运维as i would have expected (both values matching)?
Notice the big red warning in the PHP Manual!
Never expect anything when comparing floats. The result of round, even if the precision is 0, is still a float. In your particular case it happened that the result was a little bigger than expected, so casting to int resulted in equality, but for other numbers it might as well happen for it to be a little smaller than expected and casting to int won't round it, but truncate it, so you can't use casting as a workaround. (As a note, a better solution than yours would be casting to string :), but still a lousy option.)
If you need to work with amounts of money always use the BC Math extension.
For rounding with BC Math you can use this technique:
$x = '211.9452';
$x = bcadd($x, '0.005', 2);
Good luck,
Alin
Use
round()
$float_val = 4.5;
$float_val = round($float_val);
now Compare
For example a nasty case: We want to check if our ratting is greater or equal than 3.3 out of 5 while in a loop. ( This is all weird example to show a "flaw")
$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";
}
}
Now the output will be this one:
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
And the nasty part:
Testing if 3.3>=3.3
float(3.3)
string(3) "3.3"
3.3>=3.3 is FALSE
3.3 is greater or equal than 3.3 but php things not! Makes no sense right
Now if you put a ini_set('precision', 18);
before the code you can see that the evaluation actually was:
Testing if 3.29999999999999893>=3.3
float(3.29999999999999893)
string(3) "3.3"
3.29999999999999893>=3.3 is FALSE
So the $i=$i+=0.15 implicitly converts the $i to a float, which will cause this issue.
For this case the $i+=0.15 should be changed to $i=number_format($i+=0.15, 2)
精彩评论