Floating point 如何以完美的精度将字符串转换为浮点?

Floating point 如何以完美的精度将字符串转换为浮点?,floating-point,d,floating-accuracy,Floating Point,D,Floating Accuracy,我正试图用D编程语言编写一个函数来替换对C的strtold的调用。(理由:要从D使用strtold,您必须将D字符串转换为C字符串,这是低效的。而且,strtold不能在编译时执行。)我提出了一个实现,该实现大部分是有效的,但我似乎在最低有效位上失去了一些精度 下面是算法有趣部分的代码,我可以看到精度损失是从哪里来的,但我不知道如何消除它。(为了避免人们阅读,我省略了许多与核心算法无关的代码部分。)什么字符串到浮点算法将保证结果在IEEE数字行上尽可能接近字符串表示的值 real-current

我正试图用D编程语言编写一个函数来替换对C的strtold的调用。(理由:要从D使用strtold,您必须将D字符串转换为C字符串,这是低效的。而且,strtold不能在编译时执行。)我提出了一个实现,该实现大部分是有效的,但我似乎在最低有效位上失去了一些精度

下面是算法有趣部分的代码,我可以看到精度损失是从哪里来的,但我不知道如何消除它。(为了避免人们阅读,我省略了许多与核心算法无关的代码部分。)什么字符串到浮点算法将保证结果在IEEE数字行上尽可能接近字符串表示的值

real-currentPlace=10.0L^^(pointPos-ePos+1+expon);
真实ans=0;
对于(int index=ePos-1;index>-1;index--){
如果(str[index]='.'){
继续;
}
if(str[index]<'0'| | str[index]>'9'){
err();
}
自动数字=cast(int)str[index]-cast(int)'0';
ans+=数字*当前位置;
currentPlace*=10;
}
返回ans*符号;
此外,我还在旧版本中使用单元测试,它的功能如下:

assert(to!(real)(“0.456”)==0.456L);

有没有可能我的函数生成的答案实际上比编译器在解析浮点文本时生成的表示形式更精确,而编译器(用C++编写)始终与strtold完全一致,因为它在内部使用strtold解析浮点文本?

您无法在数字计算机中以完美的精度存储大多数浮点,并且开发了读取和写入浮点的精细算法

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


大卫·盖伊在改进克林格的作品,盖伊的作品很棒。我曾在嵌入式系统中使用过它们,我相信Gay的
dtoa
已经进入了许多
libc

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

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


然后按指数缩放该值,并考虑累积数字时忽略的小数点的位置。

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


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

老实说,如果您还不知道如何做,这是您真正不应该做的事情之一。它充满了陷阱,即使你成功地做到了,如果你不具备分析低级数字性能的专业知识,它的速度可能会非常慢


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

请指出您认为精度损失的来源。@John:精度损失来自两个地方:1。每次执行
ans+=digit*currentPlace
行时,我们都会进行取整,对于大多数整数i,10^i不能在IEEE 754中精确表示。请查看strod的实现,以供参考:mpfr不能这样做,如果可以,为什么不为其创建一个简单的“.di”文件?对。这就是为什么我将“完美”精度定义为与输入字符串表示的数字最接近的(32/64/80)位浮点数。Gay的源代码包含它自己的BigInt实现,它在一些临时计算中使用了它,这是相当多的代码。我认为这篇文章更容易阅读。盖伊的dtoa到处都在使用:比如Firefox、Opera、Safari、Thunderbird、KDE、Chrome、Python、MySQL、Mac OS X、J和D。自从你写了这个答案以来,人们发现了一种比盖伊更有效的算法,可以打印浮点数的最短规范值!也许更新您的答案以反映这一点?请参阅此处的“使用整数快速准确地打印浮点数”:谢谢,Josh。Grisu很有趣,但只适用于“大约99.4%”的IEEE双工;剩下的0.6%需要“用较慢的算法”处理,即
dtoa