dotancohen
dotancohen

Reputation: 31491

Why is bccomp comparing equal?

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

Answers (1)

Rick Regan
Rick Regan

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

Related Questions