C++ 是否有可能通过编程确定哪一个更快;使用余数运算符还是条件运算符?

C++ 是否有可能通过编程确定哪一个更快;使用余数运算符还是条件运算符?,c++,C++,我的理解是,在某些系统上使用余数运算符技巧会更快,但在其他系统上,条件运算符技巧会更快。有没有办法确定哪个在编译时(或运行时)更快?在循环中运行一百万次?在循环中运行一百万次?您需要对它进行基准测试 由于分支预测失误,条件语句可能代价高昂 另一方面,在许多处理器上,除法比简单比较更昂贵 它可以根据您运行的平台、它运行的循环类型、上限有多大、编译器正在执行的优化等进行选择。您需要对其进行基准测试 由于分支预测失误,条件语句可能代价高昂 另一方面,在许多处理器上,除法比简单比较更昂贵 它可以根据您运

我的理解是,在某些系统上使用余数运算符技巧会更快,但在其他系统上,条件运算符技巧会更快。有没有办法确定哪个在编译时(或运行时)更快?

在循环中运行一百万次?

在循环中运行一百万次?

您需要对它进行基准测试

由于分支预测失误,条件语句可能代价高昂

另一方面,在许多处理器上,除法比简单比较更昂贵


它可以根据您运行的平台、它运行的循环类型、上限有多大、编译器正在执行的优化等进行选择。

您需要对其进行基准测试

由于分支预测失误,条件语句可能代价高昂

另一方面,在许多处理器上,除法比简单比较更昂贵


它可以根据您运行的平台、它运行的循环类型、上限有多大、编译器正在执行的优化等进行选择。

除非您需要交叉编译程序,否则您可以将基准测试作为构建过程的一部分。根据结果,您可以选择特定的实现并继续编译应用程序。

除非您的程序需要可交叉编译,否则您可以将基准测试作为构建过程的一部分。根据结果,您可以选择一个特定的实现并继续编译应用程序。

对于大多数平台,您可以假设条件编译会更快。这是因为大多数分支预测失误代价高昂的现代体系结构都有某种形式的条件移动指令,编译器将利用它来执行请求的检查和赋值。例如,我的gcc翻译如下:

wraparound_counter & operator ++() {
    m_count = (m_count + 1) % upper_limit;
    /*if (upper == m_count)
        m_count = lower;
    ++m_count;*/
    return *this;
}
针对x86_64(和x86)的以下内容:

(从PentiumPro开始提供cmove。)

这是为手臂拇指设计的:

    addl    $1, %esi  ; %esi=n
    cmpl    $1234, %esi
    cmove   %edx, %esi ; %edx contains 0
添加r3,r3,#1
cmp r3,r1

moveq r3,#0 对于大多数平台,您可以假设条件转换速度更快。这是因为大多数分支预测失误代价高昂的现代体系结构都有某种形式的条件移动指令,编译器将利用它来执行请求的检查和赋值。例如,我的gcc翻译如下:

wraparound_counter & operator ++() {
    m_count = (m_count + 1) % upper_limit;
    /*if (upper == m_count)
        m_count = lower;
    ++m_count;*/
    return *this;
}
针对x86_64(和x86)的以下内容:

(从PentiumPro开始提供cmove。)

这是为手臂拇指设计的:

    addl    $1, %esi  ; %esi=n
    cmpl    $1234, %esi
    cmove   %edx, %esi ; %edx contains 0
添加r3,r3,#1
cmp r3,r1

moveq r3,#0 从技术上讲,如果不同时做这两件事,就不可能确定哪一件更快。就调用代码来完成工作而言,当您需要执行其中一个选项时,为时已晚。您可以有一个例程,在应用程序初始化阶段对两个示例例程进行基准测试,然后设置一个标志。但这引入了一个全新的测试,为每个目标调用增加了开销。归结起来是:

  • 用于在生成时选择适当例程的专用代码
  • 运行时基准测试(增加开销)
  • 针对您的平台,研究指令集实施细节
  • 让编译器为您完成所有这些工作

  • 除非您正在构建嵌入式系统或有非常具体的性能调整要求,否则#4是您的最佳选择。

    从技术上讲,如果不同时执行这两项操作,则无法确定哪一项更快。就调用代码来完成工作而言,当您需要执行其中一个选项时,为时已晚。您可以有一个例程,在应用程序初始化阶段对两个示例例程进行基准测试,然后设置一个标志。但这引入了一个全新的测试,为每个目标调用增加了开销。归结起来是:

  • 用于在生成时选择适当例程的专用代码
  • 运行时基准测试(增加开销)
  • 针对您的平台,研究指令集实施细节
  • 让编译器为您完成所有这些工作

  • 除非您正在构建嵌入式系统或有非常具体的性能调整要求,否则#4是您的最佳选择。

    万一
    上限
    是二的幂,您可以使用
    m_count=(m#count+1)和(上限-1)。这应该很快。但同样,只有当上限是二的幂时,它才起作用。如果存在可测量的不同,编译器将有一个优化技巧为您实现这一点。专注于使代码清晰,让编译器处理此类宏优化。“编译器将有一个优化技巧为您完成此任务”——只要您提供所需的信息。例如,它可能会失败:如果
    上限
    是一个静态成员或全局变量,实际上从未更改,但没有标记为
    常量
    ,那么编译器就不一定能够使用它可以使用的所有技巧,知道
    上限
    的实际值。整个程序优化可能会意识到它从未被修改过(因此可以被视为常量),但编译器本身不会。再想一想,
    upper\u limit
    似乎是一个成员变量,对于类的不同实例,它是不同的。因此,编译器将根据其知道的相关CPU操作的成本尽最大努力。有时,您会得到同一体系结构的不同系列,它们是指令兼容的,但成本却截然不同(IIRC ARM程序员为此诅咒xscale),因此编译器可能仍然缺少您关心的系统上的实际测试所能提供的信息。但通常编译器比C++程序员知道的更多。