はじめに
こちらは新歓ブログリレー2020 16日目の記事です。
こんにちはebiです。自分は競技プログラミングをしたりJavaScriptを書いたりしています。
この記事では競技プログラミングをするときのデバッグについて書きたいと思います。競技プログラミングについてはこの記事を読んでみてください。
デバッグってなに?
Wikipediaによると
デバッグ(debug)とは、コンピュータプログラムや電気機器中のバグ・欠陥を発見および修正し、動作を仕様通りのものとするための作業である。
とあります。要するに書いたコードのバグ取り作業のことです。
プログラムを書いていると自分の意図とは違う動作をしてしまうことがあるためそれを直して意図どおりの動作をするようにすることです。
競技プログラミングのペナルティについて
競技プログラミングではコードを提出するとジャッジされ様々なフィードバックが返ってきます。詳しくはAtCoderのサイトを見てみてください。ここでは一部を紹介します。
- AC・・・Accepted 正解です
- WA・・・Wrong Answer 間違いです
- TLE・・・Time Limit Exceeded 制限時間を超えてしまっています
AC以外の結果が出た場合、その結果によって何が原因でACされないのかわかるためそれを改善しましょう。解法とプログラムどちらに、またはその両方に欠陥があるのかどうか調べることが大切です。
C++のcoutデバッグ
どこが間違っているかを調べるときにいろいろな箇所を出力しながら確認すると思います。その過程でコードに書かれたcoutを消し忘れてWAしてしまうと悲しい気持ちになるので(自分も何回かして悲しくなりました)消さなくても良いようにすると便利です。そこでデバッグで書いた出力部分を消さなくても大丈夫なようにすると
void debug_out() { cout << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
cout << H << " ";
debug_out(T...);
}
#ifdef _DEBUG
#define debug(...) debug_out(__VA_ARGS__)
#else
#define debug(...)
#endif
これをコードに追加して、出力したいもの下のようにするとデバッグ出力されるようになります。
debug(n); // cout << n << " " << endl;がおこなわれる
debug(n,m,l) // cout << n << " " << m << " " << l << " " << endl;
そしてコンパイル時に下のようにするとデバッグ出力が有効になります。(a.cppの箇所はコンパイルしたいファイル名)
g++ a.cpp -D_DEBUG
これでデバッグ出力箇所の消し忘れをしてもWAにならないようになります。消し忘れをしてしまう人は使ってみてください。出力は自分の好みで変更可能なので可変引数などで調べてみてください。
また、cerrなどで標準エラー出力を用いいる方法もあります。
デバッグ時に気をつけていること
実際に自分がデバッグ時に確認していることを紹介します。
コンパイル時や実行時にエラーが出ていないか
エラー文が表示されると思うので読みましょう。どのようなエラーがでているかわからないときなどはエラー文をコピペしてググってみると解決の糸口が見つかるかもしれません。
計算量は大丈夫か
計算量が大きいとTLEしてしまうため計算量が制限時間内に収まるか確認しましょう。具体的には2secの場合、計算量が106 〜 107 程度だとおおよそ間に合います。それ以上だと厳しいと思っていいと思います(言語や定数倍にもよりますが)。その範囲に落とすことはできないか考えてみましょう。
オーバーフローしていないか
int型の場合、231-1よりも大きい値はオーバーフローしてしまい正確に計算できないためlong long型などを使わないといけません。
Pythonではオーバーフローは起きないため気にしないで良いです。
コーナーケースは踏んでないか
特定の値やケースの場合のみWAしてしまっていないか確認しましょう。見落としてrateを溶かすことは多々あります。
添え字は間違っていないか
多次元配列を扱っているときや多重ループをしているときによくしてしまいます。確認しましょう。
小数について
小数を扱うときは注意が必要です。C++で出力にcoutを使っている場合小数点以下が思うように出力されないことがあります。そのときは
cout << fixed << setprecision(15) << 出力したいもの << endl;
とすると小数点以下15桁まで出力されるようになるので参考にしてみてください。
最後に
読んでいただきありがとうございます。一発でコードが思うように動けば最高なんですがうまくいかないことはよくあります。上手にデバッグして思い通りのコードにできるようがんばりましょう!
予告
明日はOCTPOBさんの記事です。お楽しみに!!!