php – 为什么bcmul返回的数字与我指定的数字不同?
作者:互联网
我似乎无法在php.net文档中找到解释以下结果的任何内容:
$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"
减法结果正是我所期望的那样(我指定了一个4位数的刻度,它在结果中给了我一个).乘法结果不是(我指定了一个4位数的刻度,但它在结果中给了我一个2位数的刻度).为什么不同?
注意:我已经知道如何使用number_format()
了,我也知道0.06 === 0.0600数学.我只对理解为什么BC Math在结果的规模方面表现出不同的行为感兴趣.
注意#2:如上所述,number_format()不是这个问题的答案,所引用的“重复问题”中使用的答案都建议使用number_format().我完全知道这个函数可以用来将数字格式化为指定的精度.我只是想知道为什么这些函数的返回值有不同的比例,而不是如何修复它们.
解决方法:
PHP的BCMath函数bcmul中存在一个错误.从PHP 5.5.7开始,它仍然存在,这是撰写本文时的最新稳定版本.
如果你是browse the source code(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;
}
注意:“scale”一词是指分隔符后面的位数.
看一下分配prod_scale的行.当您调用bcmul(“0.3”,“0.2”,4)时,遍历代码,我们看到:prod_scale = MIN(2,MAX(4,MAX(1,1)));,因此prod_scale被赋值2.
并且,正如预期的那样,该函数返回小数位后的两位而不是四位数的值.与其他BCMath PHP函数不同(例如,参见PHP 5.5的BCMath doaddsub.c的第63-98行),在此函数的逻辑中没有任何地方附加尾随零.
我已将此问题和补丁提交给PHP错误跟踪系统(#66364).
标签:php,bcmath 来源: https://codeday.me/bug/20190529/1175597.html