C++ 处理器实际计算乘法是0还是1?为什么? 简本

C++ 处理器实际计算乘法是0还是1?为什么? 简本,c++,c,performance,algorithm,processors,C++,C,Performance,Algorithm,Processors,在以下行中: aData[i] = aData[i] + ( aOn * sin( i ) ); 如果aOn为0或1,处理器是实际执行乘法,还是有条件地计算出结果(0表示0,其他值表示1) 长版本 我正在研究算法性能的一致性,这在一定程度上涉及到算法的效果 假设该代码: for ( i = 0; i < iNumSamples; i++ ) aData[i] = aData[i] + ( aOn * sin( i ) ); for(i=0;i

在以下行中:

aData[i] = aData[i] + ( aOn * sin( i ) );
如果
aOn
0
1
,处理器是实际执行乘法,还是有条件地计算出结果(
0
表示
0
,其他值表示
1

长版本 我正在研究算法性能的一致性,这在一定程度上涉及到算法的效果

假设该代码:

for ( i = 0; i < iNumSamples; i++ )
    aData[i] = aData[i] + ( aOn * sin( i ) );
for(i=0;i
将提供比此代码更稳定的性能(分支预测可能会破坏性能):

for(i=0;i
aOn
0
1
,它可以在另一个线程执行循环期间切换

实际的条件计算(
+sin(i)
在上面的示例中)需要更多的处理,并且if条件必须在循环中(有许多条件,而不是像上面的示例中那样的一个条件;此外,对
aOn
的更改应该立即生效,而不是每个循环)

忽略性能一致性,两个选项之间的性能折衷是执行
if
语句和乘法所需的时间


无论如何,很容易发现,如果处理器不执行像
1
0
这样的值的实际乘法,第一个选项可能是双赢的解决方案(没有分支预测,性能更好)。

处理器执行
0
1
的定期乘法

原因是,如果处理器在每次计算之前检查
0
1
,引入该条件将需要更多的周期。虽然您将获得
0
1
乘法器的性能,但您将失去任何其他值(可能性更大)的性能

一个简单的程序可以证明这一点:

#include <iostream>
#include "cycle.h"
#include "time.h"

void Loop( float aCoefficient )
{
    float iSum = 0.0f;

    clock_t iStart, iEnd;

    iStart = clock();
    for ( int i = 0; i < 100000000; i++ )
    {
        iSum += aCoefficient * rand();
    }
    iEnd = clock();
    printf("Coefficient: %f: %li clock ticks\n", aCoefficient, iEnd - iStart );
}

int main(int argc, const char * argv[])
{
    Loop( 0.0f );
    Loop( 1.0f );
    Loop( 0.25f );

    return 0;
}

编译器很可能会对这些进行优化。我已经检查了是否进行了优化,它对
0
1
和任何其他数字的乘法器之间的相对性能没有影响(尽管在所有情况下,优化都会略微提高性能)。那么优化与处理器是否执行乘法有什么关系呢?@iamnotmaynard编译器无法对其进行优化,除非aOn是常数,但OP没有给出任何指示。您使用了什么优化级别,什么编译器,你有没有试过打印出结果的
iSum
——更重要的是,可能使用了比
rand()
稍不密集的东西,它本身做了一系列相当复杂的数学运算,可能会隐藏结果(而且因为编译器必须调用
rand()
,因为
rand()
有副作用-它会修改内部状态),但无论如何,它都无法优化它。很好的一点。无论优化级别如何(从无到
-Os
),相对性能保持不变;编译器是LLVM C++;不使用
rand()
打印
iSum
,以防止优化人员完全跳过循环;在不使用
rand()
的情况下尝试变体,例如用
sin(i)
替换变体,仍然会对所有3个乘法器产生类似的结果。我认为有可能得到一种情况,即编译器将0.0或1.0预算为“不乘法”,但同时,只有在编译器可以将系数的值视为常量的情况下,才有可能。根据处理器的类型[以及运行期间值的可预测性-换句话说,它的变化频率],使用
if
与普通乘法可能更好,也可能更好。。。继续…如果第二个线程正在修改aOn
,从技术上讲,它应该受到保护,以便两个线程不能同时更新和读取。在实践中,除非需要精确检测
on
off
,并且处理器是x86(或选定的其他类型),否则不这样做是可以的。实际实现的细节涉及GUI线程(即用户)在另一个线程进行数据处理时更改
aOn
。循环实际上是一次又一次地执行数小时。在单循环迭代规模上,精确检测
并不重要(即,只在i+1时更新是可以的-毕竟触发更改的是高度不精确的GUI线程)。所以我不明白为什么需要读/更新锁。但是更改必须在循环内生效,而不是在每个循环中生效。
#include <iostream>
#include "cycle.h"
#include "time.h"

void Loop( float aCoefficient )
{
    float iSum = 0.0f;

    clock_t iStart, iEnd;

    iStart = clock();
    for ( int i = 0; i < 100000000; i++ )
    {
        iSum += aCoefficient * rand();
    }
    iEnd = clock();
    printf("Coefficient: %f: %li clock ticks\n", aCoefficient, iEnd - iStart );
}

int main(int argc, const char * argv[])
{
    Loop( 0.0f );
    Loop( 1.0f );
    Loop( 0.25f );

    return 0;
}
Coefficient: 0.000000: 1380620 clock ticks
Coefficient: 1.000000: 1375345 clock ticks
Coefficient: 0.250000: 1374483 clock ticks