为什么打印模板元编程计算阶乘结果,比打印 for 循环计算阶乘结果更耗时

2 天前
 zcion

最近看了 effective c++ 这本书,书中有一种用模板元编程计算阶乘的骚操作,说是可以将计算从运行时转到编译期间,这样可以提高代码的执行效率。

但我尝试了下,发现并没有比使用 for 循环计算阶乘的方法快,反而花费了更多的时间,代码如下:

#include <chrono>
#include <cstdlib>
#include <iostream>
#include <new>
#include <vector>

using std::size_t;

template <unsigned x>
struct fac {
    static const size_t value = x * fac<x - 1>::value;
};

template <>
struct fac<1> {
    static const size_t value = 1;
};

// for 循环计算阶乘
size_t fori(size_t v) {
    size_t tmp = 1;
    for (size_t i = 1; i <= v; i++) {
        tmp = tmp * i;
    }
    return tmp;
}

// 利用模板元编程计算阶乘
constexpr size_t facc() { return fac<901>::value; }

void func() {
    // 模板元编程计算耗时
    auto start = std::chrono::high_resolution_clock::now();

    constexpr auto tmp = facc();
    std::cout << tmp << std::endl;

    auto end = std::chrono::high_resolution_clock::now();
    auto duration =
        std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
    std::cout << "Elapsed time: " << duration.count() << " ns"
              << std::endl;  // 输出 57466 ns

    // for 循环计算耗时
    auto start1 = std::chrono::high_resolution_clock::now();

    size_t t = fori(901);
    std::cout << tmp << std::endl;

    auto end1 = std::chrono::high_resolution_clock::now();
    auto duration1 =
        std::chrono::duration_cast<std::chrono::nanoseconds>(end1 - start1);
    std::cout << "Elapsed time: " << duration1.count() << " ns"
              << std::endl;  // 输出 1647 ns
}

int main() { func(); }

如果去掉打印,反而是利用模板元编程的更快,确实符合编译期计算提高效率的说法,但这里打印了其结果,反而花费了更多时间。

这是为什么,是编译器自个的优化策略问题还是什么?

编译器版本:gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0

786 次点击
所在节点    C++
11 条回复
zcion
2 天前
for 循环打印的结果写错了,不过不影响想要表达的意思
bfjm
2 天前
调换了一下顺序,前大后小, 应该是程序冷启动的偏差
bfjm
2 天前
可以重复测试取中位数 会更精确一点
zcion
2 天前
@bfjm 感谢大佬,重复 100 次取中位值就正常了
billccn
2 天前
一是你这样做 micro benchmark 完全不准确,因为程序运行会受到操作系统和 CPU 频率等诸多影响,需要使用 google bench 等框架测量才有意义。

二是 constexpr auto tmp 的值在编译的时候就算好了,不会耗时的,你这个代码主要测量了打印到 cout 和取高精度时间的开销。这些都是 syscall ,响应的耗时是很随机的。
vvhy
2 天前
不要把 cout 放在计时里,估计占 99%的时间
ipwx
2 天前
只有我想吐槽,900 个数连乘,肯定已经溢出了么。。。
zcion
2 天前
@billccn 感谢大佬,认识了个新东西
zcion
2 天前
@vvhy 这里好奇的点是输出一个编译期计算的结果花费了更多的时间
zcion
2 天前
@ipwx 溢出了也无所谓,主要是多次循环消耗些时间
kyingstar
1 天前
复制了 op 的 case ,尝试把迭代次数开到 10w ,然后编译了 21s 。。。感觉完全不如正常写 constexpr

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1096242

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX