私は課題に取り組んでいますが、これを実装する方法がわかりません。sadd(int x, int y)
オーバーフローしない限り、加算された数値を返す関数を作成する必要があります (その後、可能な最大の int を返すだけです)。キャストと条件ステートメントを含むいくつかのソリューションを考え出すことができましたが、それらはソリューションでは許可されていません。演算子~ ! ^ + << >> &
と|
.
2 に答える
符号付き数値の加算で、同じ符号の数値を 2 つ加算して異なる符号の結果が得られると、オーバーフローが発生しました。関連する範囲のため、符号の異なる 2 つの数値を加算するときにオーバーフローを生成することはできません。
したがって、できることは、符号ビット (2 の補数の最上位ビット) のみを監視することです。排他的 OR を使用して、2 つの元の数値の符号が異なるかどうかを取得し、それを補完して、「0」になる場合それらは異なっており、「1」は同じです。
その後、入力の 1 つに対して結果に対して排他的 OR を使用できます。同じ場合は「0」、異なる場合は「1」になります。
そして、これら 2 つの結果を合わせて、2 つの入力が同じであるが結果が異なる場合は全体として「1」を取得し、それ以外の場合は「0」を取得します。
次に、シフトと OR の組み合わせを使用して、整数全体をその値で埋めることができます。32 ビットの整数を使用していると仮定すると、最下位の 31 ビットを設定するだけで、最高値の正の整数が得られます。次にできることは、入力のいずれかの符号ビットに対するシフトと OR の同様のセットです。結果の排他的 OR。入力が負の場合、代わりに最小値の整数が得られます。
EDIT:ああ、オーバーフローがあったかどうかのビット値を使用して、intを埋めるために拡張し、オーバーフローがあった場合に返す結果とそれをANDすることによって返す値を選択し、それを補完し、通常のANDとします加算結果、次に 2 つを論理和 (または加算) します。
Presto: すべてのバイナリ ロジック、条件なし。宿題なので、実際のコードは必要ないと思いますか?
9 年後、私は以下の @gman のコメントに同意します。許可された演算子のみを使用して飽和加算を実装するには、未定義の動作に依存する必要があります —そして上記の答えは暗黙的にそうしています.
これに伴う重大なリスクは、コンパイラが未定義の動作を認識し、最適化中にそれを悪用する可能性があることです。基礎となるアーキテクチャに関する知識 (たとえば、2 の補数であること、符号付きシフトを行うこと) は、コンパイラの出力を予測するのに十分ではありません。
堅牢な製品実装は可能ですが、条件ステートメントが必要になるため、この質問には答えられません。