符号付き整数が大きくなりすぎたときにオーバーフローさせたい。次に大きいデータ型を使用せずに(またはすでにint128_tにいるときに)それを達成するにはどうすればよいですか?
たとえば、8ビット整数を使用すると19 * 12は通常260ですが1 11 10 01 00
、9番目のビットを切り取った結果、つまり-27が必要です。
符号付き整数が大きくなりすぎたときにオーバーフローさせたい。次に大きいデータ型を使用せずに(またはすでにint128_tにいるときに)それを達成するにはどうすればよいですか?
たとえば、8ビット整数を使用すると19 * 12は通常260ですが1 11 10 01 00
、9番目のビットを切り取った結果、つまり-27が必要です。
符号付きオーバーフローはCでは定義されていません。これは、実際の場合です。
1つの解決策は次のとおりです。
signed_result = (unsigned int)one_argument + (unsigned int)other_argument;
上記の解決策は、からunsigned
への最終変換で実装定義の動作を含みますint
が、未定義の動作は呼び出しません。ほとんどのコンパイルプラットフォームの実装定義の選択肢では、結果はまさに期待どおりの2の補数の結果になります。
最後に、実装定義の選択によってコンパイラが期待する動作を強制する多数のプラットフォームの1つに最適化するコンパイラは、上記のコードを明白なアセンブリ命令にコンパイルします。
あるいは、gccを使用している場合、オプション-fwrapv
/-fno-strict-overflow
はまさにあなたが望むものかもしれません。これらは、署名されたオーバーフローがラップアラウンドする標準に関して追加の保証を提供します。両者の違いはよくわかりません。
符号付き整数のオーバーフローは、C と C++ の両方の標準に従って定義されていません。特定のプラットフォームを念頭に置いていないと、目的を達成する方法はありません。
unsigned
型と同じ幅の型にアクセスできるsigned
(つまり、もう 1 つの値ビットがある)限り、標準 C の正しい方法でこれを行うことができます。でデモンストレーションするにはint64_t
:
int64_t mult_wrap_2scomp(int64_t a, int64_t b)
{
uint64_t result = (uint64_t)a * (uint64_t)b;
if (result > INT64_MAX)
return (int64_t)(result - INT64_MAX - 1) - INT64_MAX - 1;
else
return (int64_t)result;
}
これにより、問題のある中間結果は生成されません。
2の補数の符号付き整数算術(最近では妥当な仮定です)を仮定して、加算と減算のために、unsignedにキャストして計算を行います。乗算と除算の場合、オペランドが正であることを確認し、符号なしにキャストし、符号を計算して調整します。
int の目的のラッパーを作成することもできますが、それにはかなりのオーバーヘッド コードが必要になります。
未歌の整数演算を実行してから、結果を符号付き整数に詰め込みたいようです。
unsigned char a = 19;
unsigned char b = 12;
signed char c = (signed char)(a*b);
あなたが探しているものをあなたに与えるべきです。そうでない場合はお知らせください。
より大きなデータ型を使用します。GMPを使用すると、おそらく必要なすべてのスペースを確保できます。