如何手动解析字符串中的浮点数

Tho*_*mas 31 floating-point precision parsing

当然,大多数语言都有库函数,但我想自己想做.

假设浮点数是在C或Java程序中给出的(除了'f'或'd'后缀除外),例如" 4.2e1"," .42e2"或简单地" 42".通常,我们在小数点之前有"整数部分",在小数点之后有"小数部分"和"指数".这三个都是整数.

很容易找到并处理各个数字,但是如何将它们组合成类型的值floatdouble不丢失精度?

我想将整数部分乘以10 ^ n,其中n是小数部分中的位数,然后将小数部分添加到整数部分并从指数中减去n.例如,这有效地变成4.2e142e0.然后我可以使用该pow函数来计算10 ^ 指数并将结果与​​新的整数部分相乘.问题是,这种方法是否能保证最高精度?

有什么想法吗?

use*_*116 23

所有其他答案都错过了正确执行此操作的难度.您可以在此处进行第一次切割,这在某种程度上是准确的,但在您考虑IEEE舍入模式(等)之前,您将永远无法得到正确的答案.我之前写过一些天真的实现,但是有很多错误.

如果你不害怕数学的,我强烈建议您阅读大卫·戈德堡,下面的文章是什么每台计算机科学家应该知道关于浮点运算.您将更好地了解引擎盖下的内容,以及为什么这些内容都是如此布局的.

我最好的建议是从一个有效的atoi实现开始,然后从那里搬出去.你会发现很快你缺少的东西,但在几个长相的strtod的来源,你会在正确的道路上(这是一个很长很长的路径).最后,你会赞美插入diety有标准库.

/* use this to start your atof implementation */

/* atoi - christopher.watford@gmail.com */
/* PUBLIC DOMAIN */
long atoi(const char *value) {
  unsigned long ival = 0, c, n = 1, i = 0, oval;
  for( ; c = value[i]; ++i) /* chomp leading spaces */
    if(!isspace(c)) break;
  if(c == '-' || c == '+') { /* chomp sign */
    n = (c != '-' ? n : -1);
    i++;
  }
  while(c = value[i++]) { /* parse number */
    if(!isdigit(c)) return 0;
    ival = (ival * 10) + (c - '0'); /* mult/accum */
    if((n > 0 && ival > LONG_MAX)
    || (n < 0 && ival > (LONG_MAX + 1UL))) {
      /* report overflow/underflow */
      errno = ERANGE;
      return (n > 0 ? LONG_MAX : LONG_MIN);
    }
  }
  return (n>0 ? (long)ival : -(long)ival);
}
Run Code Online (Sandbox Code Playgroud)

  • 溢出调用UB; 事后你无法察觉它.在执行可能溢出的算法之前,请使用无符号类型或测试. (3认同)

Pet*_*sel 19

用于将十进制数转换为最佳浮点近似的"标准"算法是William Clinger的如何准确读取浮点数,可从此处下载.请注意,正确执行此操作需要多个精度的整数,至少需要一定的时间百分比才能处理极端情况.

另一种方法,从浮动数字打印最佳十进制数,可以在Burger和Dybvig的快速准确打印浮点数中找到,可在此下载.这也需要多精度整数运算

另请参阅David M Gay的正确舍入二进制 - 十进制和十进制 - 二进制转换,以实现双向算法.

  • 对于那些不能被谷歌打扰的人的PDF:http://www.cesura17.net/~will/professional/research/papers/howtoread.pdf (4认同)

Nil*_*nck 11

我会使用它的二进制表示直接组装浮点数.

读入一个接一个的字符,首先找到所有数字.在整数运算中执行此操作.还要跟踪小数点和指数.这个将在以后重要.

现在您可以组装浮点数.首先要做的是扫描第一组一位(从最高到最低)的数字的整数表示.

紧跟在第一位之后的位是你的尾数.

获得指数也不难.你知道第一个一位的位置,小数点的位置和科学记数法中的可选指数.合并它们并添加浮点指数偏差(我认为它是127,但请检查一些参考).

该指数应该在0到255范围内.如果它更大或更小,你有一个正或负无限数(特殊情况).

将指数存储到浮点数的24到30位.

最重要的一点就是标志.一个意味着消极,零意味着积极.

描述比实际更难,尝试分解浮点数并查看指数和尾数,你会看到它真的很容易.

顺便说一句 - 在浮点本身做算术是一个坏主意,因为你总是强迫你的尾数被截断为23个有效位.你不会那样得到精确的表达方式.

  • 该描述忘记了IEEE-754指数是二进制指数,因此尾数必须乘以:`1e2` =>`1010b` =>`1.01e11b`.当然,你不能天真地做到这一点,需要1024位数,你需要通过长乘法来做到这一点.体系浮点解析实现使用base-5 bignum执行此操作. (9认同)