wrongwrongな開発日記

情報系大学生が挑戦したことや日常を書いていきます

c++で、if文と%(剰余)のどちらが速いかを少しだけ比較

ある一定数で折り返して用いたいような数があった場合、ぱっと思いつくのは、if文を用いて初期化するやり方と、%で剰余を取る方法でしょうか。
例えば以下のようなコードです。

//if文を用いたコード
while(i < MAX) {
    if((j+=1) == 100) j = 0;
    i++;
}

//%を用いたコード
while(i < MAX){
    j = (j+1)%100;
    i++;
}

どちらのコードでも、jが100になったら0に戻す、という処理をしています。
このif文を用いて初期化する方法と、%で剰余を取るコード、どちらが高速なのか気になったので、検証を行ってみました。

実行環境

実行環境は以下の通りです。

OS Windows10 Pro
CPU Core i7 6700
MEM DDR4 2133CL13 8GBx2
コンパイラ(コンパイルオプション) g++5.3.0-3(-Wall -O3)

※CLion上のRunから実行しました
c++11でコンパイルしました

実行したコード

プロジェクト全体はGitHubに上げました。
github.com

#include <iostream>
#include <chrono>

using namespace std;

constexpr int MAX = 1000000000;

int If(){
    int i = 0;
    int j = 0;

    chrono::system_clock::time_point start, end;
    start = chrono::system_clock::now();
    while(i < MAX) {
        if((j+=1) == 100) j = 0;
        i++;
    }
    end = chrono::system_clock::now();

    cout << "if time\t\t:" << chrono::duration_cast<chrono::milliseconds>(end-start).count() <<endl;

    return i + j;
}

int Mod(){
    int i = 0;
    int j = 0;

    chrono::system_clock::time_point start, end;
    start = chrono::system_clock::now();
    while(i < MAX){
        j = (j+1)%100;
        i++;
    }
    end = chrono::system_clock::now();

    cout << "mod time\t:" << chrono::duration_cast<chrono::milliseconds>(end-start).count() <<endl;

    return i + j;
}

int main() {
    int Ifres, Modres;
    Ifres = If();
    Modres = Mod();

    cout << "if result\t:" << Ifres << '\n'
         << "mod result\t:" << Modres << endl;
    return 0;
}

実行結果

実行結果は以下の通りです。
10回ほど実行して最速だったものを選びました。

Mod If
3088[ms] 1403[ms]

結論

検証はガバガバですが、一目でわかる通りif文方が倍以上高速ですね。
大体の平均では実行時間は半分程度でしたが、iの加算処理が等しく入っていることを考えると、倍以上速いという結論は揺らがないでしょう。
あまり差が出なかったらちゃんと検証するためのコードを書くつもりでしたが、その必要も無かったです。
実験前は、加算と保存の後で更に処理を行うということで、if文を用いた処理の方が遅いのかなと思っていましたが、最適化レベルなどを弄ってみても、やはりif文を用いた方が速かったです。
恐らくif文の方が%演算子よりも分岐予測がしっかりしているためなのでしょうね。

おまけ

javaでもやってみました。
wrongwrong163377.hatenablog.com

参考にしたサイト

時間計測はこちらのサイトを参考にさせて頂きました。
qiita.com