7

私は課題に取り組んでいますが、これを実装する方法がわかりません。sadd(int x, int y)オーバーフローしない限り、加算された数値を返す関数を作成する必要があります (その後、可能な最大の int を返すだけです)。キャストと条件ステートメントを含むいくつかのソリューションを考え出すことができましたが、それらはソリューションでは許可されていません。演算子~ ! ^ + << >> &|.

4

2 に答える 2

6

符号付き数値の加算で、同じ符号の数値を 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 の補数であること、符号付きシフトを行うこと) は、コンパイラの出力を予測するのに十分ではありません。

堅牢な製品実装は可能ですが、条件ステートメントが必要になるため、この質問には答えられません。

于 2011-03-11T20:02:32.817 に答える