0
int left = std::numeric_limits<int>::min();
int right = -1;
//the code below instead of give one more than int_max gives: 18446744071562067968
unsigned long long result = left * right;

UAC を検索しようとしましたが、UAC ルールに従っても正しい出力が生成されるはずです。結果が正しくない理由はありますか?

4

3 に答える 3

4

両方のオペランドがintであるため、演算はint型内で実行されます。演算の結果が の範囲をオーバーフローするintため、結果は未定義です。

期待どおりの結果を得るには、1 つのオペランドをlong long最初にキャストします。

 unsigned long long result = left * (long long) right;

これは未定義の動作である可能性があります。できるだけ早く符号なし算術に変換する方が安全です (符号なし算術はラップしてオーバーフローしないため):

unsigned long long result = left * (unsigned long long) right;

到達した結果は次のとおりであることに注意してください0xffffffff80000000。これは、操作の実際の結果がstd::numeric_limits<int>::min()intにあり、その後符号拡張されて にキャストされたことを示しunsigned long longます。

于 2012-11-23T10:22:17.787 に答える
4

結果が型の範囲外であるため、符号付き 2 の補数の最小値にint-1 を乗算する動作は未定義です。

この場合、出力は結果が -2147483648 であることと一致しています。つまり、オーバーフローがラップアラウンドしたように見えます。署名された型のラップアラウンドに依存することはできません。署名されていない型のみです。

計算の結果を代入してもunsigned long long、計算が実行される型は変わりません。乗算を実行するとすぐに、あなたは負けます。したがって、乗算するunsigned long long 前にオペランドの 1 つを に変換します。

于 2012-11-23T10:23:37.757 に答える
0

その原因は、乗算が に関してコミットされているためですint

両方の引数はintであるため、掛け算はintagein を与え、あなたが正しかった、それは=-2147483648int_maxに相当する + 1 を与えます。int_minしたがって、実際には -2147483648 ですが、unsigned long long の場合は 18446744071562067968 と同等です。16 進コードを参照してください。

                       int_min =         80000000 
(unsigned long long) (int min) = ffffffff80000000
于 2012-11-23T10:30:58.787 に答える