我正在编写一个仅支持32位单精度浮点运算的嵌入式硬件程序。但是,我实现的算法需要64位双精度加法和比较。我试图使用两个double
的元组模拟float
数据类型。因此,double d
将被模拟为包含元组的struct
:(float d.hi, float d.low)
。
使用词典排序,比较应该是直截了当的。然而,添加有点棘手,因为我不确定应该使用哪个基数。它应该是FLT_MAX
吗?我怎样才能检测到携带?
如何做到这一点?
编辑(清晰度):我需要额外的有效数字,而不是额外的范围。
答案 0 :(得分:77)
double-float是一种技术,它使用单精度数对,几乎达到单精度算术精度的两倍,同时略微降低单精度指数范围(由于中间下溢和远端溢出)范围)。基本算法由T.J.开发。 Dekker和William Kahan在20世纪70年代。下面我列出了两篇最近的论文,展示了这些技术如何适应GPU,但是这些论文中涵盖的大部分内容都适用于独立于平台,因此应该对手头的任务有用。
http://hal.archives-ouvertes.fr/docs/00/06/33/56/PDF/float-float.pdf GuillaumeDaGraça,David Defour 在图形硬件上实现float-float操作符, 第7届实数和计算机会议,RNC7。
http://andrewthall.org/papers/df64_qf128.pdf 安德鲁塔尔 用于GPU计算的扩展精度浮点数。
答案 1 :(得分:11)
这并不简单。
浮点数(IEEE 754单精度)有1个符号位,8个指数位和23位尾数(好吧,实际上是24位)。
双精度(IEEE 754双精度)有1个符号位,11个指数位和52位尾数(实际上是53位)。
您可以使用其中一个浮点数的符号位和8个指数位,但是如何从另一个浮点数中获得3个指数位和29位尾数?
也许其他人可以想出一些聪明的东西,但我的回答是“这是不可能的”。 (或者至少,“不比使用64位结构和实现自己的操作更容易”)
答案 2 :(得分:6)
这取决于您想要执行的操作类型。如果您只关心加法和减法,Kahan Summation可能是一个很好的解决方案。
答案 3 :(得分:5)
如果您需要精度和宽范围,则需要双精度浮点的软件实现,例如SoftFloat。
(另外,基本原则是将每个值的表示(例如64位)分成三个组成部分 - 符号,指数和尾数;然后根据指数的差异移动一个部分的尾数,基于符号位添加或减去其他部分的尾数,并可能通过移动尾数并相应地调整指数来重新规范化结果。一路上,有很多细节需要考虑,以便避免不必要的准确性损失,并处理特殊值,如无穷大,NaN和非规范化数字。)
答案 4 :(得分:3)
这不实用。如果是这样,每个嵌入式32位处理器(或编译器)都会通过这样做来模拟双精度。就目前而言,没有人知道。他们中的大多数只是将float替换为double。
如果您需要精确度而不是动态范围,最好的选择是使用固定点。如果编译器支持64位,这也会更容易。
答案 5 :(得分:3)
考虑到23个以上高精度的所有约束,我认为最有效的方法是实现自定义算术包。
快速调查显示,Briggs的 doubledouble C ++库应该满足您的需求,然后是一些。请参阅this。[*]默认实现基于double
以实现30个有效数字计算,但很容易重写以使用float
来实现13或14个有效数字。如果注意将加法操作与相似的幅度值分开,那么这可能足以满足您的要求,只在最后的操作中将极值加在一起。
请注意,注释提到了x87控制寄存器。我没有查看详细信息,但这可能会使代码太不便于您使用。
[*]该文章链接了C ++源代码,但只有gzipped tar不是死链接。
答案 6 :(得分:1)
另一种可能有用的基于软件的解决方案:GNU MPFR
它会处理许多其他特殊情况,并且允许您以其他方式处理自己的任意精度(优于64位双精度)。
答案 7 :(得分:0)
这类似于double-double arithmetic的许多编译器在仅具有硬件double
计算支持的某些计算机上使用的long double
。它也被用作旧版NVIDIA GPU上的浮动浮动,没有double
支持。见Emulating FP64 with 2 FP32 on a GPU。这样计算将比软件浮点库快得多。
然而,在大多数微控制器中,float
没有硬件支持,所以它们纯粹是用软件实现的。因此,使用float-float
可能不会提高性能并引入一些内存开销来保存指数的额外字节。
如果您确实需要更长的尾数,请尝试使用自定义浮点库。您可以选择适合您的任何内容,例如,如果只需要40位尾数和7位指数,则更改库以适应您自己的新48位浮点类型。无需再花时间计算/存储不必要的16位。但是这个库应该非常高效,因为编译器的库通常对它们自己的float类型进行汇编级优化。