使用 bcdiv,我不能用科学记数法除以小浮点数:
工作代码 :
bcscale(30);
$a = '1' ;
$b = '0.00000001';
$result = bcdiv($a, $b);
var_dump($result);
结果为 :
字符串(20) "100000000.0000000000"
非工作代码:
bcscale(30);
$a = '1' ;
$b = '1e-8';
$result = bcdiv($a, $b);
var_dump($result);
结果为 :
警告:bcdiv() [function.bcdiv]:在 C:\wamp\www\utilitaires\test_bcdiv.php on line XX NULL
我怎样才能正确地进行这种划分,同时减少精度损失?
这是因为,实际上,bcmath
不支持科学记数法。手册中没有提到它,但如您所见,在它的实现中使用了参数转换,它被命名为 php_str2num
:
static void php_str2num(bc_num *num, char *str TSRMLS_DC)
{
char *p;
if (!(p = strchr(str, '.'))) {
bc_str2num(num, str, 0 TSRMLS_CC);
return;
}
bc_str2num(num, str, strlen(p+1) TSRMLS_CC);
}
等等bc_str2num
:
bc_str2num (bc_num *num, char *str, int scale TSRMLS_DC)
{
int digits, strscale;
char *ptr, *nptr;
char zero_int;
/* Prepare num. */
bc_free_num (num);
/* Check for valid number and count digits. */
ptr = str;
digits = 0;
strscale = 0;
zero_int = FALSE;
if ( (*ptr == '+') || (*ptr == '-')) ptr++; /* Sign */
while (*ptr == '0') ptr++; /* Skip leading zeros. */
while (isdigit((int)*ptr)) ptr++, digits++; /* digits */
if (*ptr == '.') ptr++; /* decimal point */
while (isdigit((int)*ptr)) ptr++, strscale++; /* digits */
if ((*ptr != ' ') || (digits+strscale == 0))
{
*num = bc_copy_num (BCG(_zero_));
return;
}
/* Adjust numbers and allocate storage and initialize fields. */
strscale = MIN(strscale, scale);
if (digits == 0)
{
zero_int = TRUE;
digits = 1;
}
*num = bc_new_num (digits, strscale);
/* Build the whole number. */
ptr = str;
if (*ptr == '-')
{
(*num)->n_sign = MINUS;
ptr++;
}
else
{
(*num)->n_sign = PLUS;
if (*ptr == '+') ptr++;
}
while (*ptr == '0') ptr++; /* Skip leading zeros. */
nptr = (*num)->n_value;
if (zero_int)
{
*nptr++ = 0;
digits = 0;
}
for (;digits > 0; digits--)
*nptr++ = CH_VAL(*ptr++);
/* Build the fractional part. */
if (strscale > 0)
{
ptr++; /* skip the decimal point! */
for (;strscale > 0; strscale--)
*nptr++ = CH_VAL(*ptr++);
}
}
-不难看出它会在科学记数法上失败(评论很好)。也许文档需要更新(隐含地提及)。
可能的解决方案是在应用bcmath
函数之前将字符串转换为纯视图