Why does bcmul return a number with a scale different from the one I specified?

I can not find anything in the php.net documentation that explains the following results:

$ php -r 'var_dump(bcsub("0.3", "0.2", 4));'
string(6) "0.1000"
$ php -r 'var_dump(bcmul("0.3", "0.2", 4));'
string(4) "0.06"

The result of the subtraction is exactly what I expect from it (I indicated a 4-digit scale, and this gave me the result). The result of the multiplication is not (I indicated a 4-digit scale, but it gave me a 2-digit result). Why is the difference?

Note: I already know how to use it number_format(), and I also know that 0.06 === 0.0600mathematically, I'm just curious to understand why BC Math seems to act differently in terms of the scale of the result.

Note # 2: As mentioned above, number_format()this is not the answer to this question, and the answers used in the mentioned “duplicate question” are all advised with help number_format(). I know very well that this function can be used to format a number to the specified accuracy. I'm just curious to know WHY the return values ​​for these functions have different scales, NOT how to fix them so that they do it.

+4
source share
1 answer

There is an error in the PHP BCMath function bcmul. It is still present in PHP 5.5.7, the latest stable version at the time of this writing.

(PHP 5.5 BCMath recmul.c), :

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;
}

. "" .

, prod_scale. bcmul("0.3", "0.2", 4), , : prod_scale = MIN(2,MAX(4,MAX(1,1)));, prod_scale 2.

, , , . BCMath PHP (, . 63-98 PHP 5.5 BCMath doaddsub.c), .


PHP (# 66364).

+5

All Articles