3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

競プロにおけるC++の実行速度について

3
Last updated at Posted at 2025-12-05

はじめに

この記事はComputer Society Advent Calender 2025の5日目の記事です。
4日目

この記事

6日目
執筆者は競プロ歴、C++使用歴ともに半年程度の初心者なので至らぬ点も多々あるとは思いますが温かい目で見守っていただけると幸いです。

本題

競技プログラミングをしている際mod計算をする場面があると思います。その際modの法が$10^9$を超えても使えるように__int128を使おうとしたのですが調べてみるとlong longと違い__int128は四則演算をする際に複数の命令に分割するため実行速度が遅くなってしまうという問題があるらしいとわかりました。
そこで実際どれくらい差があるのか気になったのでC++の有名な以下の高速化コード

#define endl "\n"
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);

と共に実測していきたいと思います。

実行環境

今回はAtCoderのコードテスト(新ジャッジシステム)C++ (GCC 15.2.0)を用いました。

検証

1.#define endl "\n"

これはcoutの際に使用するendlをデフォルトの関数endlを使わず、改行の文字列を使うことによってendlのたびにflushをしてしまい余計な処理が起こることを防ぐ手法です。flushはそれまでにたまっているバッファにたまっている出力を強制的に出力させる効果がありますが、インテラクティブな問題以外の複数回出力する問題(クエリ問題など)ではまとめてから出力させればいいので複数回flushするのは余計に時間がかかることになるのを防ぐために使います。

2.std::ios::sync_with_stdio(false);

これは標準入力オブジェクトとC言語の標準入力ストリームの同期を解除する関数です。これを使うとcinとscanfを併用することができなくなる代わりに同期の重い処理をしなくて済むため速くなるというものです。

3.std::cin.tie(nullptr);

C++ではふつうはcinとcoutを結んでおく(tie)ことによってcinをする前にcoutのflushを行うようになっています。ただ前述のとおりflushを行う処理はそれなりに重いため入力の数が多い問題なんかではTLEする危険性もあるためそれを防ぐために使います。

4.long long__int128

今回の本題です。今回は$1≤i≤N$の$i^4$の総和を998244353で割ったあまりを求めるプログラムで速度差を測りました。


検証に使ったプログラムは最後の使用コードに置いておきました。

測定結果

注意
実行する状況によって今回の結果と異なる結果が出る可能性がありますので結果はあくまで参考程度に見てください。

1. #define endl "\n"
あり(1e7) なし(1e7) あり(1e8) なし(1e8)
実行時間 396ms 3465ms 6942ms >10000ms
メモリ 79724KiB 79748KiB 859680KiB 236004KiB
2. std::ios::sync_with_stdio(false);,3. std::cin.tie(nullptr)

いずれも$10^7$回の処理における検証

2 あり 2 なし 3 あり 3 なし
実行時間 100ms 136ms 110ms 107ms
メモリ 10608KiB 10504KiB 10580KiB 10480KiB
4.long long__int128
ll(1e7) __int128(1e7) ll(1e8) __int128 (1e8)
実行時間 36ms 71ms 343ms 828ms
メモリ 3552KiB 3480KiB 3524KiB 3616KiB

結論

endlでflushを使わないようにする対処はTLEするかしないかレベルで影響するがsync_with_stdio(false)cin.tie(nullptr)は実行時間に大きな差を与えないことがわかりました。また今回調べたかったlong long__int128に関しては定数倍で落ちる可能性があるアルゴリズムを使っている際は関係があるという程度のものであるという結果になりました。
記事を書くという行為自体初めてで読みづらい点があったとは思いますが最後まで読んでいただきありがとうございました。

使用コード

1.#define endl "\n"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ovfl = __int128;
using vi = vector<int>;
using vll = vector<ll>;
using vs = vector<string>;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
#define rep(i,n) for (int i = 0; i < (int) (n); i++)
#define all(v) (v).begin(), (v).end()
#define endl '\n'
#define YES(b) (b) ? cout << "YES" << endl : cout << "NO" << endl
#define Yes(b) (b) ? cout << "Yes" << endl : cout << "No" << endl
#define yes(b) (b) ? cout << "yes" << endl : cout << "no" << endl

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll N = 1e7;
    rep(i,N) {
        cout << i << endl;
    }
    return 0;
}
2,3.sync_with_stdio(false),cin.tie(nullptr)
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ovfl = __int128;
using vi = vector<int>;
using vll = vector<ll>;
using vs = vector<string>;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
#define rep(i,n) for (int i = 0; i < (int) (n); i++)
#define all(v) (v).begin(), (v).end()
#define endl '\n'
#define YES(b) (b) ? cout << "YES" << endl : cout << "NO" << endl
#define Yes(b) (b) ? cout << "Yes" << endl : cout << "No" << endl
#define yes(b) (b) ? cout << "yes" << endl : cout << "no" << endl

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll N = 1e7;
    rep(i,N) {
      char s;
      cin >> s;
      cout<<s;
    }
    return 0;
}
4.long longと__int128
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ovfl = __int128;
using vi = vector<int>;
using vll = vector<ll>;
using vs = vector<string>;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
#define rep(i,n) for (int i = 0; i < (int) (n); i++)
#define all(v) (v).begin(), (v).end()
#define endl '\n'
#define YES(b) (b) ? cout << "YES" << endl : cout << "NO" << endl
#define Yes(b) (b) ? cout << "Yes" << endl : cout << "No" << endl
#define yes(b) (b) ? cout << "yes" << endl : cout << "no" << endl

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    constexpr ll N = 1e7;
    constexpr __int128 m = 998244353;
    __int128 ans = 0;
    rep(i,N) {
        __int128 tmp = i;
        tmp *= tmp;
        tmp *= tmp;
        tmp %= m;
        ans += tmp;
        ans %= m;
    }
    cout << (ll) ans << endl;
    return 0;
}
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?