当前位置: 首页 > 知识库问答 >
问题:

比较函数中的FMA指令破坏了严格的弱排序特性

朱兴运
2023-03-14

C命名的需求比较要求比较函数遵循严格的弱排序属性。这用于许多标准库函数,例如std::sort。

许多现代CPU支持融合乘加运算,这种运算可以高效地计算< code>a b * c,并且无需对乘法结果进行舍入。这意味着有些情况下,FMA运算的结果不同于单独的乘法和加法运算。GCC的FMA代码生成由< code>-ffp-contract标志控制,默认启用。

编译器在比较函数中生成FMA指令时,可能会出现严格弱排序属性(静默)不再成立的情况。这可能会导致std::排序和其他函数在运行时失败并崩溃。

请考虑以下示例:

struct S {
    double a;
    double b;
};

bool compare(const volatile S& s1, const volatile S& s2) {  // Volatile to prevent compile-time computations
    return s1.a * s1.b - s2.a * s2.b < 0.0;
}

int main() {
    const double a = 1 + 0x1.0p-52;
    const double b = 1 - 0x1.0p-52;

    volatile S s1{a, b};  // Volatile to prevent compile-time computations
    volatile S s2{1.0, 1.0};

    std::cout << compare(s1, s2) << '\n';
    std::cout << compare(s2, s1) << '\n';
}

预期产出为

1
0

但是,在支持FMA的平台上(启用后,这在GCC上也是默认的),结果是

0
0

(合同通用条款11.2,<代码>-O3-三月=哈斯韦尔)

清楚地表明弱有序性质< del >不被实施不再成立。

为什么默认启用这个潜在危险的功能?除了禁用FMA代码生成之外,还可以做些什么来避免这种情况?

共有1个答案

孙钱青
2023-03-14

确保一个严格的弱顺序的责任在于你,而不是编译器。如果你简单地返回true忽略参数,这显然不是一个严格的弱顺序。编译器无法“强制”弱顺序。

当然,您的代码并没有那么糟糕。它只包含一个隐藏的假设,即s1.a*s1.b-s2.a*s2.b

同样,当比较的实现是错误的时,编译器无法“强制”弱排序。

请注意,如果传递选项-fast-math,则编译器可能会将转换为s1.a*s1.b-s2.a*s2.b

 类似资料:
  • 许多C标准算法,如,假设比较器是一个严格的弱排序,并且不能假设具有任何其他(不错的)属性。但是很多时候确实有更多的属性,而不仅仅是一个严格的弱排序。特别是,很多时候是一个严格的总顺序(所以特别是,对于所有和:,或总是正确的。例如,通常的

  • 这是我目前所掌握的: video.cpp文件: video.h文件: 我真的不知道如何正确实现气泡排序。我在youtube上查阅了多个不同的视频和stackoverflow上的帖子,但我似乎无法弄清楚如何在我的类中对一个特定的参数进行排序。 我的教授给了我们这些关于在我们班内排序的指示: 在对视频进行排序时,您需要能够确定两个视频对象应该如何排序。最简单的方法是编写成员函数来处理类视频中的比较。例

  • 尝试编写一些干净的JS排序函数。下面是我的模板中一个按钮的click处理程序,它调用各个方法按不同的属性排序。 它调用下面的方法。它的工作很好,这是很好的! 我遇到的问题是,我已经有了大约4个这样的排序方法,我想把if语句放入它们自己的函数中,以便更好地编写干巴巴的代码。所以我尝试了下面的方法,但是compareFunction甚至从来没有调用过GET。我做错了什么?

  • 所以我正在使用一些预先存在的比较器,它们比较两个元组中的某些值,如果第一个大于第二个,则返回true,否则返回false。这是其中之一的代码: 现在,我有一个字典,里面有许多上面比较的类型的元组条目。我想以相反的顺序对它们进行排序,但我真的不知道如何完成。我在想这样的事情: 但是我不知道向比较器传递什么,因为每个比较器都有两个参数(subInfo1、subInfo2)。我不能更改比较器函数。

  • 在C Sort函数中,第三个可选参数是用于对对象进行排序的比较器。如果我们传入的比较器更少,我们将以递增的顺序获得对象。(如果比较器的评估结果为真,则不会更改位置,否则将对元素进行交换!)我的理解正确吗? 按照同样的方式,如果我们将一个较少的比较器传递给优先级队列,我们应该得到一个最小堆(如果基础数据结构被选择为向量,对象将按递增顺序排序)。如果我们调用top(),将返回向量的第一个元素,这是最小

  • 我的代码如下所示: 我想使用比较器按降序对数组排序,但它总是显示 第14行:错误:未找到适合排序的方法(int[],int,int,匿名比较器) 有人能指出问题出在哪里吗?非常感谢!