提问人: 提问时间:7/21/2011 最后编辑:phuclv 更新时间:9/10/2020 访问量:15398
使用 2 个“float”模拟“double”
Emulate "double" using 2 "float"s
问:
我正在为仅支持 32 位单精度浮点运算的嵌入式硬件编写程序。但是,我正在实现的算法需要 64 位双精度加法和比较。我正在尝试使用两个 s 的元组来模拟数据类型。因此,a 将被模拟为包含元组的 a:。double
float
double d
struct
(float d.hi, float d.low)
使用词典排序应该很简单。然而,添加有点棘手,因为我不确定我应该使用哪个底座。应该是吗?我怎样才能检测到携带?FLT_MAX
这怎么能做到呢?
编辑(清晰度):我需要额外的有效数字而不是额外的范围。
答:
这并不简单。
浮点数(IEEE 754 单精度)有 1 个符号位、8 个指数位和 23 位尾数(嗯,实际上是 24 位)。
双精度(IEEE 754 双精度)具有 1 个符号位、11 个指数位和 52 位尾数(有效为 53)。
您可以使用其中一个浮点数中的符号位和 8 个指数位,但是您将如何从另一个浮点数中获得 3 个指数位和 29 位尾数?
也许其他人能想出一些聪明的东西,但我的回答是“这是不可能的”。(或者至少,“不比使用 64 位结构并实现自己的操作更容易”)
评论
这是不切实际的。如果是这样,每个嵌入式 32 位处理器(或编译器)都会通过这样做来模拟双精度。就目前而言,据我所知,没有人这样做。他们中的大多数只是替代.float
double
如果您需要精度而不是动态范围,最好的选择是使用定点。如果编译器支持 64 位,这也将更容易。
评论
双精度
时,或者在某些编译器中,当硬件支持不可用时,它被广泛使用以实现接近四倍精度double
如果您同时需要精度和宽范围,则需要双精度浮点的软件实现,例如 SoftFloat。
(此外,基本原理是将每个值的表示(例如64位)分解为三个组成部分 - 符号,指数和尾数;然后根据指数的差异移动一个部分的尾数,根据符号位增加或减去另一部分的尾数,并可能通过移动尾数并相应地调整指数来重新归一化结果。在此过程中,为了避免不必要的准确性损失,并处理特殊值,例如无穷大、NaN 和非规范化数字,需要考虑许多繁琐的细节。
这在一定程度上取决于您要执行的操作类型。如果您只关心加法和减法,那么 Kahan Summation 可能是一个很好的解决方案。
评论
双浮点数是一种使用单精度数对实现单精度算术精度几乎两倍的技术,同时单精度指数范围略有减小(由于范围远端的中间下溢和溢出)。基本算法是由 T.J. 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安德鲁·索尔 用于 GPU 计算的扩展精度浮点数。
评论
constexpr
考虑到 23 级以上高精度的所有限制,我认为最有效的方法是实现自定义算术包。
一项快速调查显示,Briggs 的 doubledouble C++ 库应该可以满足您的需求,然后是一些。看这个。[*]默认实现基于实现 30 个有效数字的计算,但它很容易被重写以用于实现 13 或 14 个有效数字。如果注意将具有相似量级值的加法运算分开,只在最后的运算中将极值相加,这可能足以满足您的要求。double
float
但要注意,评论中提到弄乱 x87 控制寄存器。我没有检查细节,但这可能会使代码太不可移植,无法供您使用。
[*]C++源代码由该文章链接,但只有gzip压缩的tar不是死链接。
另一个可能有用的基于软件的解决方案:GNU MPFR
它可以处理许多其他特殊情况,并允许任意精度(优于 64 位双精度),否则您必须自己照顾自己。
评论
这类似于许多编译器在某些仅具有硬件计算支持的机器上用于长
双精度的双精度算术。它也被用作不支持的旧 NVIDIA GPU 上的浮点数。请参阅在 GPU 上使用 2 个 FP32 模拟 FP64。这样,计算将比软件浮点库快得多。double
double
然而,在大多数微控制器中,没有对 s 的硬件支持,因此它们纯粹是在软件中实现的。因此,使用可能不会提高性能,并引入一些内存开销来节省额外的指数字节。float
float-float
If you really need the longer mantissa, try using a custom floating-point library. You can choose whatever is enough for you, for example change the library to adapt a new 48-bit float type of your own if only 40 bits of mantissa and 7 bits of exponent is needed. No need to spend time for calculating/storing the unnecessary 16 bits anymore. But this library should be very efficient because compiler's libraries often have assembly level optimization for their own type of float.
评论
double
double
1.0E+20
1.0E-03
double
1.0E-16
1.0E+20 + 1.0E-03
1.0E+20
double