##書いた目的
オーバーフローについての備忘録
##演算中はその演算で使われている数の型の範囲内で計算される
うまく言葉にできてないですが笑
こんなコードを実行すると(abc172Dのために書いていた途中のコードです)
#include <iostream>
typedef long long ll;
using namespace std;
int main()
{
int n;
n = 10000000;
ll ans = 0;
ll max_i;
ll ans_i = 0;
int max_i2;
for (int i = 1; i <= 5; i++)
{
max_i = n / i;
ans = (max_i * (max_i + 1) * i) / 2;
cout << "max_i:" << max_i << " "
<< "ans:" << ans << endl;
max_i2 = n / i;
ans_i = (max_i2 * (max_i2 + 1) * i) / 2;
cout << (max_i2 * (max_i2 + 1) * i) / 2 << endl;
cout << "max_i2:" << max_i2 << " "
<< "ans_i:" << ans_i << endl;
}
return 0;
}
出力は
max_i:10000000 ans:50000005000000
143223616
max_i2:10000000 ans_i:143223616
max_i:5000000 ans:25000005000000
-999630016
max_i2:5000000 ans_i:-999630016
max_i:3333333 ans:16666668333333
47741205
max_i2:3333333 ans_i:47741205
max_i:2500000 ans:12500005000000
-497315008
max_i2:2500000 ans_i:-497315008
max_i:2000000 ans:10000005000000
-826348736
max_i2:2000000 ans_i:-826348736
こうなります。
オーバーフローを起こして演算結果がmax_i2
を使っている方でおかしくなっています。
同じ演算をしていて、違うところはmax_i
の型はlong long
でmax_i2
の型はint
(変数名がくそですみません)。
この結果から考えられることは、代入先の変数の型がlong long
であっても代入する前の演算がint
で行われていたら演算結果がint
の範囲をオーバーしたらオーバーフローを起こしてしまうということ。
####追加の検証
#####変数を使わなかったら。
こういう計算
cout << (5000000 * (5000000 + 1) * 2) / 2 << endl;
結果は
-999630016
とオーバーフローを起こしていた。
演算に使われている全ての値がint
の範囲内なのに演算途中でint
の範囲をオーバーしてしまうから。
intの範囲内の数同士の計算でintの範囲を超えてしまうとまずいらしい。
ちなみにこの時はコンパイラが怒ってくれる
test.cpp:33:22: warning: overflow in expression; result is -999630016 with type 'int' [-Winteger-overflow]