如何以完美的准确度将字符串转换为浮点数?

时间:2010-02-01 00:26:09

标签: floating-point d floating-accuracy

我正在尝试用D编程语言编写一个函数来替换对C的strtold的调用。 (基本原理:要使用来自D的strtold,你必须将D字符串转换为C字符串,这是低效的。另外,strtold不能在编译时执行。)我想出了一个主要有效的实现,但是我似乎在最不重要的位上失去了一些精确度。

算法的有趣部分的代码如下,我可以看到精度损失来自哪里,但我不知道如何摆脱它。 (我遗漏了许多与核心算法无关的代码部分,以节省人们的阅读。)什么字符串到浮点算法将保证结果尽可能接近IEEE编号换行到字符串表示的值。

real currentPlace = 10.0L ^^ (pointPos - ePos + 1 + expon);

real ans = 0;
for(int index = ePos - 1; index > -1; index--) {
    if(str[index] == '.') {
        continue;
    }

    if(str[index] < '0' || str[index] > '9') {
        err();
    }

    auto digit = cast(int) str[index] - cast(int) '0';
    ans += digit * currentPlace;
    currentPlace *= 10;
}

return ans * sign;

另外,我正在使用旧版本的单元测试,其中包括:

assert(to!(real)("0.456") == 0.456L);

我的函数生成的答案是否可能比解析浮点文字时编译器生成的表示更准确,但编译器(用C ++编写)总是与strtold完全一致,因为它使用了strtold内部用于解析浮点文字?

5 个答案:

答案 0 :(得分:10)

ClingerSteele & White开发了用于读写浮点的精确算法。

有一个回顾展here以及对实现的一些参考。

David Gay的paper改善了Clinger的工作,同性恋的implementation in C很棒。我在嵌入式系统中使用它们,我相信Gay的dtoa已经进入了许多libc

答案 1 :(得分:2)

老实说,如果你还不知道怎么做,这就是你真正不应该做的事情之一。它充满了陷阱,即使你设法做到正确,如果你没有分析低级数字性能的专业知识,它可能会非常缓慢。

也就是说,如果你真的决定编写自己的实现,那么正确性的最佳参考是David Gay的“正确圆二进制 - 十进制和十进制 - 二进制转换”(postscript version)。您还应该研究他的参考实现(在C中),这些实现可以在Netlib上找到。

答案 2 :(得分:1)

首先将数字累加为整数值,忽略小数点和指数。您仍然会使用浮点累加器,但是您没有小数部分,这可以避免精度损失,因为无法准确表达浮点数。 (你还可以忽略超出浮点数精度的小数位 - 代表32位IEEE浮点数的8位数。)

如果您愿意,可以使用64位整数来累积数字,但是如果您这样做,则必须小心忽略会导致溢出的额外数字。 (在确定指数时,您可能仍需要考虑这些数字)

然后使用指数缩放此值,同时考虑在累积数字时忽略的小数点的位置。

答案 3 :(得分:0)

您无法在数码电脑中以完美的精度存储大多数花车

答案 4 :(得分:0)

您为每个数字创建一个浮点数,然后将这些数字加在一起。由于浮点数不精确,但四舍五入到一定数量的二进制数字,因此在存储单个数字并将其相加时会涉及很小的不精确度。因此,将单个数字的浮点数加在一起可能会产生舍入误差较小的结果。

示例为0.1 + 0.02,如果表示为浮点数,则等于0.12。 (要验证这一点,只需尝试用您喜欢的编程语言进行比较)