Reputation: 31491
I usually test float comparison by comparing the absolute value of the difference of the floats to an arbitrarily small delta:
php > echo abs( (0.1+0.1+0.1) - 0.3 ) < 0.0001 ;
1
php > echo abs( 0.3 - (0.1+0.1+0.1) ) < 0.0001 ;
1
Today I discovered the PHP function bccomp() which supposedly performs the comparison, however it does require it's arguments to be strings (and returns 0
if the values are in fact equal)!
From the fine manual, and confirmed in my PHP interpretter:
echo bccomp('1', '2') . "\n"; // -1
echo bccomp('1.00001', '1', 3); // 0
echo bccomp('1.00001', '1', 5); // 1
However, these comparisons are not returning what I would expect:
php > echo bccomp( strval(0.1+0.1+0.1), strval(0.3) ); // Expect 0
0
php > echo bccomp( strval(0.1+0.1+0.1), strval(0.4) ); // Expect 1
0
php > echo bccomp( strval(0.1+0.1+0.1), strval(0.2) ); // Expect -1
0
To be sure, let's ensure that strval()
is returning what we think it should:
php > echo strval(0.1+0.1+0.1);
0.3
php > echo strval(0.3);
0.3
Why in bccomp()
returning 0
in the problematic examples above?
Upvotes: 1
Views: 1114
Reputation: 3512
You need to specify the scale (3rd parameter to bccomp()), as done in the examples you cite from the manual. I tried it with a scale of 17:
php > echo bccomp( strval(0.1+0.1+0.1), strval(0.3), 17 ); // Expect 0
0
php > echo bccomp( strval(0.1+0.1+0.1), strval(0.4), 17 ); // Expect -1
-1
php > echo bccomp( strval(0.1+0.1+0.1), strval(0.2), 17 ); // Expect 1
1
That is the correct output (your expectations were wrong -- you had 1 and -1 reversed).
I guess for what you're trying to do you would adjust the scale to match your delta (e.g., 4). But in general I'd be careful using bccomp() with 'stringified' floating-point results.
EDIT: If you set the precision higher, e.g., ini_set('precision', 17);, the result of the first line will change, reflecting that 0.1 + 0.1 + 0.1 is greater than 0.3; you'll get 1 instead of 0.
Upvotes: 2