Question

I have a simple piece of code as below.

$amount = 447274.44882;
$rate = 0.00001;

echo floatNumber(bcmul($amount, $rate, 8), 8);

This outputs 0.00000000 when it should be 4.47274449. If I change the rate to 0.0001 then it outputs the correct number, anything higher than 4 decimals and it reports 0.

Am I doing something wrong or is this a known limitation or something? Seems quite a big one if that's the case.

Was it helpful?

Solution

If you cast 0.00001 to string using the default settings (and that's what will happen if you feed bcmul with floats since it expects strings) you'll get this:

var_dump( (string)0.00001 );
string(6) "1.0E-5"

It isn't clearly documented but bcmath functions apparently return cast to zero when faced to invalid input:

var_dump( bcadd('Hello', 'world!', 8) );
var_dump( bcadd('33', 'Foo', 8) );
var_dump( bcdiv('33', 'Foo', 8) );
string(10) "0.00000000"
string(11) "33.00000000"
Warning: bcdiv(): Division by zero
NULL

The whole idea of arbitrary precision libraries is to overcome the limitations of base 2 arithmetic and fixed size storage. Thus you'd need this:

var_dump( bcmul('447274.44882', '0.00001', 8) );
string(10) "4.47274448"

This is great to do math with 100-digit numbers but not particularly useful for simple rounding. In fact, the extension doesn't round at all—it merely truncates:

var_dump( bcmul('20.01', '1.444', 3) );
var_dump( bcmul('20.01', '1.444', 2) );
var_dump( bcmul('20.01', '1.444', 1) );
var_dump( bcmul('20.01', '1.444', 0) );
string(6) "28.894"
string(5) "28.89"
string(4) "28.8"
string(2) "28"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top