【问题标题】:How to write portable floating point arithmetic in c++?如何在 C++ 中编写可移植的浮点运算?
【发布时间】:2009-06-11 17:17:54
【问题描述】:

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

【问题讨论】:

    标签: c++ floating-point


    【解决方案1】:

    非 IEEE 754

    一般来说,你不能。在一致性和性能之间总是需要权衡取舍,而 C++ 将其交给了您。

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

    对于这些,您可以使用 16 位或 32 位定点算术(但您甚至可能会发现 long 仅支持初级 - 而且通常,div 非常昂贵)。不过这样会比内置的定点运算慢很多,基本的四次运算后就很痛苦了。

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

    IEEE 754 - 一致性

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

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

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

    另外——我学到了很多东西——打印和解析功能在平台之间不一定一致,可能也是由于数字不准确。

    浮动

    一个常见的误解是浮点运算本质上比双倍快。通常仅通过较少的缓存未命中来处理大型浮点数组会更快。

    注意浮点精度。它可以在很长一段时间内“足够好”,但我经常看到它失败的速度比预期的要快。由于 SIMD 支持,基于浮点的 FFT 可以更快,但很早就为音频处理生成显着伪影。

    【讨论】:

    • 还有很多显卡在双倍模式下工作,当它必须将浮点或更糟糕的下降转换为某些 OpenGL 兼容模式时,您可能会显着减速。
    【解决方案2】:

    使用固定点。

    但是,如果您想接近可能进行可移植浮点运算的领域,您至少需要使用controlfp 以确保一致的 FPU 行为以及确保编译器强制执行关于浮点运算的 ANSI 一致性.为什么选择ANSI?因为这是一个标准。

    即使这样,您也不能保证可以生成相同的浮点行为;这也取决于您运行的 CPU/FPU。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 我不认为 IEEE 754 在 C++ 中得到保证。
      • 不,但是你能想象任何支持 C++ 但不使用它的合理操作系统!
      • 虽然我当然可以想象一个,但我不得不承认我不知道任何现代的 :)
      • 许多嵌入式和信号处理平台只提供定点算法。
      • 我只是在想,当我写“合理”的时候!有趣的是有多少嵌入式系统支持 C++,尽管 RTTI 和 STL 无一例外都不是真正的 C++。
      【解决方案4】:

      便携是一回事,在不同平台上产生一致的结果是另一回事。根据您要执行的操作,编写可移植代码应该不会太难,但在任何平台上获得一致的结果实际上是不可能的。

      【讨论】:

        【解决方案5】:

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

        std::numeric_limits、std::numeric_limits、std::numberic_limits 等...

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-11-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-05-24
            • 1970-01-01
            • 2015-04-13
            • 1970-01-01
            相关资源
            最近更新 更多