int同士の割り算で小数点以下が消えるバグ
int型同士の割り算は小数点以下を切り捨てたint型の結果になるバグです。その結果をdouble型に代入しても、切り捨てはすでに終わったあとなので元には戻りません。
なぜエラーが出ないのか
出力: 3.0
(エラーなし)- C++は何も報告しません。コンパイルも実行も正常に完了するためです
出力: 3.0- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 #include <iostream> 2 #include <iomanip> 3 int main() { 4 int total = 7; 5 int count = 2; 6 double avg = total / count; ^ 7 std::cout << std::fixed << std::setprecision(1) << avg << std::endl; 8 return 0; 9 }
int同士の割り算は小数点以下を切り捨てたint型の結果になります。その結果をdoubleに代入しても、切り捨てはすでに終わったあとで元には戻りません。片方をdoubleにキャストしてから割る必要があります。
直し方: / を / 1.0 / にします。
パターン2
1 #include <iostream> 2 #include <iomanip> 3 int main() { 4 int minutes = 100; 5 double hours = minutes / 60; ^ 6 std::cout << std::fixed << std::setprecision(2) << hours << std::endl; 7 return 0; 8 }
minutesと60はどちらもint型なので、/は整数の割り算になり小数点以下が切り捨てられます。結果はdouble型の変数に代入されても、切り捨てられたあとの値がそのまま入るだけです。
直し方: / を / 1.0 / にします。
パターン3
1 #include <iostream> 2 #include <iomanip> 3 int main() { 4 int price = 999; 5 int people = 4; 6 double share = price / people; ^ 7 std::cout << std::fixed << std::setprecision(2) << share << std::endl; 8 return 0; 9 }
999 / 4は整数の割り算として計算され249になり、そのあとでdoubleに変換されます。先にdoubleへ変換してから割らなければ、小数部分は復元できません。
直し方: / を / 1.0 / にします。
パターン4
1 #include <iostream> 2 #include <iomanip> 3 int main() { 4 int wins = 3; 5 int games = 8; 6 double rate = wins / games; ^ 7 std::cout << std::fixed << std::setprecision(2) << rate << std::endl; 8 return 0; 9 }
winsもgamesもint型なので、/は整数除算になり小数部分が切り捨てられます。
直し方: / を / 1.0 / にします。
パターン5
1 #include <iostream> 2 #include <iomanip> 3 int main() { 4 int total = 50; 5 int weeks = 3; 6 double perWeek = total / weeks; ^ 7 std::cout << std::fixed << std::setprecision(2) << perWeek << std::endl; 8 return 0; 9 }
整数同士の割り算が先に切り捨てられてからdoubleに代入されるため、あとから小数部分を復元できません。
直し方: / を / 1.0 / にします。
よくある誤解
「代入先がdouble型なら自動的に小数の割り算になる」というのは誤解です。C++は代入する直前ではなく、演算そのものを行う時点でのオペランドの型を見て割り算の種類を決めます。
実務での勘所
C++ではdouble(a) / bやstatic_cast<double>(a) / bのように書きますが、実務ではC言語由来の(double)aよりstatic_castが推奨されます。C形式のキャストは状況に応じて複数の異なる種類の変換(数値変換、ポインタの再解釈など)をまとめて1つの記法で行ってしまうため、意図しない危険な変換まで許してしまうことがあります。static_castは「数値としての妥当な変換」だけに限定されるため、書き間違いをコンパイラがより厳しくチェックしてくれます。