为什么`else if(!var)`中的循环比`else`中的循环快?

时间:2014-04-11 16:22:23

标签: c++ loops for-loop

我有两个块做同样的事情。

if(print) for(int i = 0; i < numt; i++) if(primes[i]) {
    printf("%d\n", i);
    numprimes++;
}
    //fast
else if(!print) for(int i = 0; i < numt; i++) if(primes[i]) {
    numprimes++;
}

if(print) for(int i = 0; i < numt; i++) if(primes[i]) {
    printf("%d\n", i);
    numprimes++;
}
    //very slow
else for(int i = 0; i < numt; i++) if(primes[i]) {
    numprimes++;
}

我估计第一个比第二个快一倍。为什么是这样?效果发生在多个编译器中(Mingw,msvc)。默认情况下,print为false,但您可以使用命令行args更改它。我在两种情况下都没有运行程序。这真是个谜......

拆卸: block 1 block 2

整个文件:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>

int main(int argc, char* argv[]) {
    int numt = 1000000;
    int sqrtt = sqrt(numt);
    bool* primes = malloc(numt*sizeof(int));
    int numprimes = 0;
    bool print = true;
    time_t start, end;


    if(argc > 2) if(!strcmp(argv[2], "-np")) print = false;
    if(argc > 1) sscanf(argv[1], "%d", &numt);


    if(primes == NULL) {
        printf("error in allocation");
        return 1;
    }

    memset(primes, true, numt);

    primes[0] = false;
    primes[1] = false;

    for(long long id = 1; id <= sqrtt; id++) if(primes[id]) for(long long cl = id*id; cl <= numt; cl+= id) primes[cl] = false;

    start = clock();
    //start block
    if(print) for(int i = 0; i < numt; i++) if(primes[i]) {
        printf("%d\n", i);
        numprimes++;
    }
    else for(int i = 0; i < numt; i++) if(primes[i]) { //diff line
        numprimes++;
    }
    //end block

    end = clock();

    free(primes);

    printf("%d Primes before %d took %d", numprimes, numt, end-start);

    return 0;
}

exe fast:https://drive.google.com/file/d/0B8ujl0shCPcHRTRENzFyeHpkd0U/edit?usp=sharing

exe慢:https://drive.google.com/file/d/0B8ujl0shCPcHcmZQNDlLLTZ3OWM/edit?usp=sharing

视频演示:http://youtu.be/45L4qkaPDmE

这是一个要比较的c ++版本:

#include <iostream>
#include <vector>
#include <string>
#include <math.h>
#include <ctime>
#include <Windows.h>
#include <omp.h>
#include <thread>

using namespace std;

int main(int argc, char* argv[])
{

    const double s = GetTickCount();
    long long numt; //max number to compute to
    if(argc < 2) {
        cout << "Usage: "<<argv[0]<<" <primes until...>" << endl;
        return 1;
    }

    else if(atoi(argv[1])<1) {
        cout << "Usage: "<<argv[0]<<" <primes until...>" << endl;
        return 1;
    }
    numt = atol(argv[1])+1;

    bool skipprint = false;

    if(argc >=3) if(!strcmp(argv[2], "noprint")) skipprint = true;

    vector<bool> primes(numt); 

    primes.assign(numt, true); 

    primes[0] = false; //0 is not prime
    primes[1] = false; //1 is also not prime but we do not want to eliminate all multiples of 1 (all numbers)
    //#pragma omp parallel
    {
        const long long sqrtt = sqrt(numt); //don't need to go past sqrt(n) to eliminate all composites

        //#pragma omp parallel for
        for(long long id = 1; id <= sqrtt; id++) {
            if(primes[id]) {
                //#pragma omp for
                for(long long cl = id*id; cl <= numt; cl+= id) primes[cl] = false;
            }
        }

            //#pragma omp parallel for
            //for(long long cl = l*l; cl <= numt; cl+= l) primes[cl] = false;
    }
    const double m = GetTickCount();
    unsigned long long count = 0;




    //this is the block
    if(!skipprint) for(long long l = 2; l<numt; l++) if(primes[l]) {
        cout << l << endl;
        count ++;
    }
    if(skipprint) for(long long l = 2; l<numt; l++) if(primes[l]) count ++;
    //this is the end of the block




    const double e = GetTickCount();
    cout << endl;
    cout << count << " primes less than or equal to " << numt-1 << endl;
    cout << "Calculation took " << m-s << " ms";
    if(!skipprint) cout << " and printing took " << e-m << " ms";
    else cout << " and counting took " << e-m << " ms";
    cout <<"." << endl;

    return 0;
}

1 个答案:

答案 0 :(得分:10)

对发布的代码的善意编辑掩盖了真正的问题。

原始代码是:

if(print) for(int i = 0; i < numt; i++) if(primes[i]) {
    printf("%d\n", i);
    numprimes++;
}
    //fast
else if(!print) for(int i = 0; i < numt; i++) if(primes[i]) {
    numprimes++;
}

if(print) for(int i = 0; i < numt; i++) if(primes[i]) {
    printf("%d\n", i);
    numprimes++;
}
    //very slow
else for(int i = 0; i < numt; i++) if(primes[i]) {
    numprimes++;
}

请注意原始代码段中的最后一个else if(!print)else for()如何绑定到之前的if(primes[i]),而不是初始if(print)测试。 编辑添加了原始代码中没有的大括号并更改了其行为。

如果没有花括号,则两个代码段会执行不同的操作,因此无法比较性能。 我认为nimsson不寻常的编码风格导致了这个问题。