如何在c ++中编写可移植的浮点运算?

时间:2009-06-11 17:17:54

标签: c++ floating-point

假设您正在编写一个执行大量浮点运算的C ++应用程序。假设这个应用程序需要在合理范围的硬件和操作系统平台上可移植(例如32位和64位硬件,Windows和Linux都是32位和64位版本......)。

您如何确保所有平台上的浮点算法都相同?例如,如何确保32位浮点值在所有平台上实际上都是32位?

对于整数,我们有stdint.h但似乎没有浮点等价物。


[编辑]

我得到了非常有趣的答案,但我想为这个问题增加一些精确度。

对于整数,我可以写:

#include <stdint>
[...]
int32_t myInt;

并确保无论我在哪个(C99兼容)平台上,myInt都是32位整数。

如果我写:

double myDouble;
float myFloat;

我确定这会在所有平台上分别编译为64位和32位浮点数吗?

6 个答案:

答案 0 :(得分:9)

非IEEE 754

一般来说,你不能。在一致性和性能之间总是需要权衡,而C ++会向你提供这些权利。

对于没有浮点运算的平台(如嵌入式和信号处理处理器),您不能使用C ++“本机”浮点运算,至少不能这样。虽然软件层是可能的,但对于这种类型的设备来说肯定是不可行的。

对于这些,你可以使用16位或32位定点算法(但你甚至可能发现只支持基本的长 - 而且经常,div非常昂贵)。然而,这将比内置的定点算术慢得多,并且在基本的四次操作之后变得很痛苦。

我没有遇到过以不同于IEEE 754的格式支持浮点的设备。根据我的经验,您最好的选择是希望达到标准,否则您通常最终会围绕设备的功能构建算法和代码。当sin(x)突然花费1000倍时,您最好选择一种不需要它的算法。

IEEE 754 - 一致性

我在这里找到的唯一不可移植性是当你期望跨平台的比特结果相同时。最大的影响是优化者。同样,您可以交换准确性和速度以保持一致性。大多数编译器都有一个选项 - 例如Visual C ++中的“浮点一致性”。但请注意,这总是准确超出标准的保证。

为什么结果不一致? 首先,FPU寄存器通常具有比双倍(例如80位)更高的分辨率,因此只要代码生成器不将值存储回来,就可以以更高的精度保持中间值。

其次,由于精度有限,像a*(b+c) = a*b + a*c这样的等价不精确。尽管如此,优化器(如果允许)可以使用它们。

另外 - 我学到了很多困难 - 打印和解析功能不一定在不同平台上保持一致,可能也是由于数字不准确。

一种常见的误解是浮动操作本质上比双重快。通过单独减少缓存未命中,处理大型浮点数组的速度更快。

小心浮动精度。它可以在很长一段时间内“足够好”,但我经常看到它失败的速度比预期的要快。由于支持SIMD,基于浮点数的FFT可以更快,但是在音频处理的早期阶段就会产生显着的假象。

答案 1 :(得分:4)

使用固定点。

但是,如果您想要接近可能进行可移植浮点运算的领域,您至少需要使用controlfp来确保一致的FPU行为,并确保编译器在浮动方面强制执行A​​NSI一致性点操作。为何选择ANSI?因为它是标准。

即便如此,您也无法保证可以生成相同的浮点行为;这也取决于你正在运行的CPU / FPU。

答案 2 :(得分:2)

这应该不是问题,IEEE 754已经定义了浮动布局的所有细节。

可存储的最大值和最小值应在limits.h中定义。

答案 3 :(得分:2)

便携式是一回事,在不同平台上产生一致的结果是另一回事。根据您的尝试,编写可移植代码应该不会太困难,但在任何平台上获得一致的结果几乎是不可能的。

答案 4 :(得分:0)

我相信“limits.h”将包含C库常量INT_MAX及其兄弟。但是,最好使用“限制”及其定义的类:

std::numeric_limits<float>, std::numeric_limits<double>, std::numberic_limits<int>, etc...

答案 5 :(得分:0)

如果您假设在其他系统上获得相同的结果,请先阅读What could cause a deterministic process to generate floating point errors。您可能会惊讶地发现,在同一台计算机上的不同运行中,您的浮点运算甚至不同!