There's a bug in PHP's BCMath function bcmul
. It's still present as of PHP 5.5.7, the latest stable release as of this writing.
If you browse the source code (PHP 5.5's BCMath recmul.c), you'll see the relevant function:
void
bc_multiply (bc_num n1, bc_num n2, bc_num *prod, int scale TSRMLS_DC)
{
bc_num pval;
int len1, len2;
int full_scale, prod_scale;
/* Initialize things. */
len1 = n1->n_len + n1->n_scale;
len2 = n2->n_len + n2->n_scale;
full_scale = n1->n_scale + n2->n_scale;
prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
/* Do the multiply */
_bc_rec_mul (n1, len1, n2, len2, &pval, full_scale TSRMLS_CC);
/* Assign to prod and clean up the number. */
pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
pval->n_value = pval->n_ptr;
pval->n_len = len2 + len1 + 1 - full_scale;
pval->n_scale = prod_scale;
_bc_rm_leading_zeros (pval);
if (bc_is_zero (pval TSRMLS_CC))
pval->n_sign = PLUS;
bc_free_num (prod);
*prod = pval;
}
Note: The word "scale" refers to the number of digits after the separator.
Take a look at the line where prod_scale
is assigned. When you invoke bcmul("0.3", "0.2", 4)
, walking through the code, we see: prod_scale = MIN(2,MAX(4,MAX(1,1)));
, so prod_scale
is assigned a value of 2
.
And, as expected, the function returns a value with two, not four, digits after the decimal place. Unlike in the other BCMath PHP functions (e.g., see lines 63-98 of PHP 5.5's BCMath doaddsub.c), nowhere in this function's logic does it append the trailing zeros.
I've submitted this issue and a patch to the PHP bug tracking system (#66364).