10

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

4

5 回答 5

10

ClingerSteele & White开发了用于读取和写入浮点数的精细算法。

这里有一个回顾以及对实现的一些参考。

David Gay 的论文改进了 Clinger 的工作,以及 Gay在 C 中的实现都很棒。我已经在嵌入式系统中使用过它们,而且我相信 Gay 已经dtoa进入了许多libc's。

于 2010-02-01T00:57:43.133 回答
2

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

也就是说,如果您真的决定编写自己的实现,正确性的最佳参考是 David Gay 的“正确舍入二进制-十进制和十进制-二进制转换”(后记版本)。您还应该研究他在Netlib上提供的参考实现(用 C 语言) 。

于 2010-02-01T01:21:57.307 回答
1

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

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

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

于 2010-02-01T01:05:15.500 回答
0

您无法在数字计算机中以完美的精度存储大多数浮点数

于 2010-02-01T00:54:47.600 回答
0

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

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

于 2010-02-01T01:05:56.563 回答