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

nim*_*son -4 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++;
}
Run Code Online (Sandbox Code Playgroud)

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++;
}
Run Code Online (Sandbox Code Playgroud)

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

拆卸: 块1 块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;
}
Run Code Online (Sandbox Code Playgroud)

exe快速: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;
}
Run Code Online (Sandbox Code Playgroud)

Bla*_*ace 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++;
}
Run Code Online (Sandbox Code Playgroud)

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++;
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • @nimsson暂时放松一下,看看刚刚发生了什么.原来是一个比编程更好的人类行为课程.你完全无视每个充满理智并且对你的错误视而不见的人,这些持怀疑态度的愤怒的答案正在增长.精心打算的编辑搞砸了所有这些.等等. (2认同)
  • @nimsson:你的错误非常有名; 这被称为*悬空其他问题*.这里的故事的寓意是,首先,在处理多个`if`和`else`子句时总是使用大括号,其次,当某些东西看起来不能正常工作时,**在调试器中逐步执行代码**. (2认同)