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

递归的意外性能结果

鲁旭
2023-03-14

我想知道为什么我用这两对递归的明显例子得到了意想不到的表现。

相同的递归函数在结构中更快(rec2 VS rec1),相同的递归模板函数在虚拟参数中更快(rec4 VS rec3)!

使用更多参数的C++函数是否更快?!

下面是尝试的代码:

#include <QDebug>
#include <QElapsedTimer>


constexpr std::size_t N = 28;
std::size_t counter = 0;


// non template function which take 1 argument
void rec1(std::size_t depth)
{
    ++counter;
    if ( depth < N )
    {
        rec1(depth + 1);
        rec1(depth + 1);
    }
}

// non template member which take 2 arguments (implicit this)
struct A
{
    void rec2(std::size_t depth)
    {
        ++counter;
        if ( depth < N )
        {
            rec2(depth + 1);
            rec2(depth + 1);
        }
    }
};

// template function which take 0 argument
template <std::size_t D>
void rec3()
{
    ++counter;
    rec3<D - 1>();
    rec3<D - 1>();
}

template <>
void rec3<0>()
{
    ++counter;
}

// template function which take 1 (dummy) argument
struct Foo
{
    int x;
};

template <std::size_t D>
void rec4(Foo x)
{
    ++counter;
    rec4<D - 1>(x);
    rec4<D - 1>(x);
}

template <>
void rec4<0>(Foo x)
{
    ++counter;
}


int main()
{
    QElapsedTimer t;
    t.start();
    rec1(0);
    qDebug() << "time1" << t.elapsed();
    qDebug() << "counter" << counter;
    counter = 0;
    A a;
    t.start();
    a.rec2(0);
    qDebug()<< "time2"  << t.elapsed();
    qDebug()<< "counter"  << counter;
    counter = 0;
    t.start();
    rec3<N>();
    qDebug()<< "time3"  << t.elapsed();
    qDebug()<< "counter"  << counter;
    counter = 0;
    t.start();
    rec4<N>(Foo());
    qDebug()<< "time4"  << t.elapsed();
    qDebug()<< "counter"  << counter;

    qDebug() << "fin";

    return 0;
}

我得到这样的输出:

time1 976 
counter 536870911 
time2 341 
counter 536870911 
time3 241 
counter 536870911 
time4 201 
counter 536870911 
fin

我已启用:Windows 8.1/i7 3630QM/Latch Qt ChainTool/C++14

共有1个答案

姜育
2023-03-14

我终于能够在Visual Studio2015社区上看到这一点。检查已编译代码的反汇编,rec1和rec2是递归的。它们在生成的代码中非常相似,尽管rec2有更多的指令,但它运行的速度略快。rec3和rec4都为模板参数中的D的所有不同值生成一系列函数,在这种情况下,编译器消除了许多函数调用,消除了其他函数调用,并添加了一个较大的值来计数。(例如,rec4<10>只是将2047添加到count并返回。)

因此,您看到的性能差异主要是由于编译器如何优化每个版本,而代码如何流经CPU的细微差异也是一个因素。

我的结果(以秒为单位的时间),用/ox/O2编译:

time1 1.03411
counter 536870911
time2 0.970455
counter 536870911
time3 0.000866
counter 536870911
time4 0.000804
counter 536870911
 类似资料:
  • 问题内容: 开放赏金:好吧,老板需要答案,我需要加薪。这似乎不是一个冷缓存问题。 更新: 我没有遵循以下建议。客户统计数据如何得出一组有趣的数字。 #temp 与 @temp INSERT,DELETE和UPDATE语句的数量0对1 受INSERT,DELETE或UPDATE语句影响的行0 vs 7647 SELECT语句数0 vs 0 SELECT语句返回的行0 vs 0 交易数量0对1 最有趣

  • 各种各样的书籍、文章、博客帖子表明,将递归函数重写为尾部递归函数可以加快速度。毫无疑问,对于生成斐波那契数或计算阶乘等琐碎情况,它会更快。在这种情况下,有一种典型的重写方法,即使用“辅助函数”和用于中间结果的附加参数。 尾部递归很好地描述了尾部递归函数和非尾部递归函数之间的差异,以及如何将递归函数转换为尾部递归函数。对于这种重写来说什么是重要的-函数调用的数量是相同的(重写之前/之后),不同之处在

  • 在我看来,我的缓冲区包含关于最后一个数据包步骤(路由器->my home)的信息,这些信息解释了为什么TTL值是254以及为什么我用Traceroute找到了相同的两个IP: $>traceroute qwant.com traceroute to qwant.com(194.187.168.99),30跳最大,60字节数据包 172.17.0.1(172.17.0.1)0.026 ms 0.01

  • 本文向大家介绍数据结构 二叉树的递归与非递归,包括了数据结构 二叉树的递归与非递归的使用技巧和注意事项,需要的朋友参考一下 数据结构 二叉树的递归与非递归 实例代码:  先序遍历(递归法)   后序遍历      感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

  • 问题内容: 给定一个变量,该变量包含巴黎时区的日期时间2000-01-01 00:01(冬季afaik中为UTC + 2): 我希望转换为UTC会导致日期时间为1999-12-31 22:01,但是却得到了: 我想念什么? 谢谢 问题答案: 不幸的是 ,在许多时区使用标准构造函数的参数“不起作用” 。 但是对于没有夏令时转换的时区来说是安全的,例如UTC: 您会注意到: “ LMT + 0:09:

  • 我有以下代码: 为什么它会打印Java流?