63

我正在为仅支持 32 位单精度浮点运算的嵌入式硬件编写程序。然而,我正在实现的算法需要 64 位双精度加法和比较。我正在尝试double使用两个floats 的元组来模拟数据类型。所以 adouble d将被模拟为 astruct包含元组:(float d.hi, float d.low)

使用字典顺序进行比较应该很简单。然而,添加有点棘手,因为我不确定我应该使用哪个基础。应该是FLT_MAX吗?以及如何检测进位?

如何才能做到这一点?


编辑(清晰):我需要额外的有效数字而不是额外的范围。

4

8 回答 8

92

double-float 是一种技术,它使用成对的单精度数来实现几乎是单精度算术精度的两倍,同时略微减小单精度指数范围(由于范围远端的中间下溢和溢出) . 基本算法由 TJ Dekker 和 William Kahan 在 1970 年代开发。下面我列出了两篇相当近期的论文,展示了这些技术如何适用于 GPU,但是这些论文中涵盖的大部分材料都适用于独立于平台,因此应该对手头的任务有用。

https://hal.archives-ouvertes.fr/hal-00021443 Guillaume Da Graça,David Defour 在图形硬件上实现浮点-浮点运算符,第 7 届实数和计算机会议,RNC7。

http://andrewthall.org/papers/df64_qf128.pdf Andrew Thall 用于 GPU 计算的扩展精度浮点数。

于 2011-07-21T01:17:20.897 回答
11

This is not going to be simple.

A float (IEEE 754 single-precision) has 1 sign bit, 8 exponent bits, and 23 bits of mantissa (well, effectively 24).

A double (IEEE 754 double-precision) has 1 sign bit, 11 exponent bits, and 52 bits of mantissa (effectively 53).

You can use the sign bit and 8 exponent bits from one of your floats, but how are you going to get 3 more exponent bits and 29 bits of mantissa out of the other?

Maybe somebody else can come up with something clever, but my answer is "this is impossible". (Or at least, "no easier than using a 64-bit struct and implementing your own operations")

于 2011-07-21T00:02:14.307 回答
9

这在一定程度上取决于您要执行的操作类型。如果您只关心加法和减法,Kahan Summation可能是一个很好的解决方案。

于 2011-07-21T00:51:56.193 回答
7

如果您需要精度和宽范围,您将需要双精度浮点的软件实现,例如SoftFloat

(此外,基本原理是将每个值的表示(例如 64 位)分解为其三个组成部分 - 符号、指数和尾数;然后根据指数的差异移动一个部分的尾数,添加到或根据符号位减去另一部分的尾数,并可能通过移动尾数和相应调整指数来重新归一化结果。精度,并处理特殊值,例如无穷大、NaN 和非规范化数字。)

于 2011-07-21T00:47:03.523 回答
5

考虑到超过 23 个量级的高精度的所有限制,我认为最有成效的方法是实现自定义算术包。

一项快速调查显示 Briggs 的doubledouble C++ 库应该能满足您的需求,然后再满足一些需求。见这个。[*] 默认实现是基于double实现 30 位有效数字计算,但它很容易重写以float实现 13 或 14 位有效数字。如果注意隔离具有相似幅度值的加法运算,仅在最后一次运算中将极值加在一起,这可能足以满足您的要求。

但请注意,评论提到搞乱 x87 控制寄存器。我没有检查细节,但这可能会使代码太不便携,不适合您使用。


[*] 该文章链接了 C++ 源代码,但只有 gzip 压缩的 tar 不是死链接。

于 2011-07-21T01:43:15.230 回答
3

另一个可能有用的基于软件的解决方案:GNU MPFR
它处理许多其他特殊情况并允许您必须自行处理的任意精度(优于 64 位双精度)。

于 2011-07-21T11:43:28.473 回答
2

这不切实际。如果是这样,每个嵌入式 32 位处理器(或编译器)都会通过这样做来模拟双精度。就目前而言,我所知道的没有人这样做。他们中的大多数只是float替代double.

如果您需要精度而不是动态范围,最好的选择是使用定点。如果编译器支持 64 位,这也会更容易。

于 2011-07-21T00:10:51.070 回答
1

这类似于许多编译器在某些仅支持硬件计算的机器上使用的双双运算。它还可以在不支持的旧 NVIDIA GPU 上用作浮点浮点。请参阅在 GPU 上使用 2 个 FP32 模拟 FP64。这样计算将比软件浮点库快得多。long doubledoubledouble

然而,在大多数微控制器中,没有对floats 的硬件支持,因此它们纯粹在软件中实现。因此,使用float-float可能不会提高性能并引入一些内存开销来节省额外的指数字节。

如果您真的需要更长的尾数,请尝试使用自定义浮点库。您可以选择适合您的任何内容,例如,如果只需要 40 位尾数和 7 位指数,则更改库以适应您自己的新 48 位浮点类型。无需再花时间计算/存储不必要的 16 位。但是这个库应该非常高效,因为编译器的库通常针对自己的浮点类型进行汇编级优化。

于 2013-08-02T07:28:31.147 回答