如何将字符串准确转换为浮点数?

问题描述 投票:10回答:5

我正在尝试用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用于解析浮点文字?

floating-point d floating-accuracy
5个回答
10
投票

[ClingerSteele & White开发了用于读写浮点的优良算法。

具有回顾性here以及对实现的一些引用。

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


2
投票

老实说,如果您还不知道该怎么做,这是您不应该做的事情之一。它充满了陷阱,即使您没有做对它,但如果您不具备分析低级数值性能的专业知识,也可能会非常慢。

就是说,如果您真的决心编写自己的实现,那么正确性的最佳参考就是David Gay的“正确舍入的二进制十进制和十进制二进制转换”(postscript version)。您还应该研究他的参考实现(用C语言编写),可以在Netlib上找到。


1
投票

首先将数字累积为整数值,而忽略小数点和指数。您仍将使用浮点累加器,但没有小数部分,这将避免精度损失,因为无法精确表示浮点数。 (您也应该忽略超出浮点数精度的小数位数来表示-32位IEEE浮点数的8位数字。)

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

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


0
投票

您不能在数字计算机中以完美的精度存储大多数浮子


0
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.