小编Ika*_*ros的帖子

std::fabs(a * b) 和 std::fabs(a) * std::fabs(b) 的区别

我正在处理一些数字代码,我正在查看编译器输出。一个特殊的案例让我觉得很奇怪:

在实数中,它成立abs(a) * abs(b) = abs(a * b)。我希望在浮点数中也是如此。但是,优化既不是由 clang 也不是由 g++ 执行的,我想知道我是否遗漏了一些细微的差异。然而,两个编译器都意识到abs(abs(a) * abs(b)) = abs(a) * abs(b).

这是相关的一段代码:

#include<cmath>

double fabsprod1(double a, double b) {
    return std::fabs(a*b);
}
double fabsprod2(double a, double b) {
    return std::fabs(a) * std::fabs(b);
}
double fabsprod3(double a, double b) {
    return std::fabs(std::fabs(a) * std::fabs(b));
}
Run Code Online (Sandbox Code Playgroud)

这是带有 gcc-10.1(撰写本文时的当前稳定版本)和 -O3 的 Godbolt 中令人困惑的编译器输出:https ://godbolt.org/z/ZEFPgF

值得注意的是,即使使用 -Ofast,据我所知,它对允许的转换更为宽松,也不会执行此优化。

正如@Scheff 在评论中指出的那样,double 和 float 不是实数。但我也没有看到带有浮点类型的极端情况,例如将 Infinity 或 NaN 作为参数,可能会产生不同的输出。

c++ x86 g++ compiler-optimization clang++

12
推荐指数
1
解决办法
201
查看次数

Clang 对递归 constexpr 函数的好奇错过了优化

今天我想测试一下,Clang 如何转换两个函数的递归幂,并注意到即使使用已知指数,即使使用 constexpr 也不会优化递归。

#include <array>
constexpr unsigned int pow2_recursive(unsigned int exp) {
    if(exp == 0) return 1;
    return 2 * pow2_recursive(exp-1);
}

unsigned int pow2_5() {
    return pow2_recursive(5);
}
Run Code Online (Sandbox Code Playgroud)

pow2_5 被编译为对 pow2_recursive 的调用。

pow2_5():                             # @pow2_5()
        mov     edi, 5
        jmp     pow2_recursive(unsigned int)     # TAILCALL
Run Code Online (Sandbox Code Playgroud)

但是,当我在需要在编译时知道结果的上下文中使用结果时,它将在编译时正确计算结果。

unsigned int pow2_5_arr() {
    std::array<int, pow2_recursive(5)> a;
    return a.size();
}
Run Code Online (Sandbox Code Playgroud)

被编译为

pow2_5_arr():                        # @pow2_5_arr()
        mov     eax, 32
        ret
Run Code Online (Sandbox Code Playgroud)

以下是 Godbolt 中完整示例的链接:https ://godbolt.org/z/fcKef1

那么,我在这里错过了什么吗?有什么可以在运行时改变结果的原因吗,pow2_5 不能像 pow2_5_arr 一样优化?

c++ clang compiler-optimization constexpr clang++

5
推荐指数
0
解决办法
65
查看次数

标签 统计

c++ ×2

clang++ ×2

compiler-optimization ×2

clang ×1

constexpr ×1

g++ ×1

x86 ×1