繁体   English   中英

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

[英]How to write portable floating point arithmetic in c++?

假设您正在编写一个执行大量浮点运算的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位浮点数吗?

非IEEE 754

一般来说,你不能。 在一致性和性能之间总是需要权衡,而C ++会为您提供帮助。

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

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

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

IEEE 754 - 一致性

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

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

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

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

浮动

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

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

使用固定点。

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

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

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

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

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

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

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

如果您假设您将在另一个系统上获得相同的结果,请阅读什么可能导致确定性过程首先生成浮点错误 您可能会惊讶地发现,在同一台机器上的不同运行中,您的浮点运算甚至不同!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM