【问题标题】:bcdiv using very small float with scientific notation cause "Division by zero" errorbcdiv 使用带有科学记数法的非常小的浮点数导致“除以零”错误
【发布时间】:2014-03-20 02:58:39
【问题描述】:

使用 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 在第 XX 行 NULL

我怎样才能正确地进行这种划分,同时减少精度损失?

【问题讨论】:

  • 您确定bc-函数支持科学记数法吗?我无法在文档中对此做出任何暗示。
  • @Sirko 它不支持。但是 - 你是对的,这需要隐含地澄清

标签: php division zero scientific-notation bcmath


【解决方案1】:

那是因为,实际上,bcmath 不支持科学记数法。手册中没有提到它,但是正如你所看到的,它使用了implementation 参数转换,它被命名为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 != '\0') || (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 函数之前将您的字符串转换为普通视图

【讨论】:

  • 是的,感谢您确认这一点。我将编写我自己的转换函数 exp float > full str。我无法使用现有的 php 函数(如 number_format 或只是类型转换......)获得我想要的结果。如果您有任何出色而简单的想法...再次感谢 Eric
  • 这是个好问题。我问了here。我有解决方案,但肯定社区会提出更好的方法
猜你喜欢
  • 1970-01-01
  • 2021-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-08
  • 2016-06-28
  • 2013-05-31
相关资源
最近更新 更多