2

次の (疑似 C++) コードがあるとします。

float x=100, a=0.1;
unsigned int height = 63, width = 63;
unsigned int hw=31;
for (int row=0; row < height; ++row)
{
    for (int col=0; col < width; ++col)
    {
        float foo = x + col - hw + a * (col - hw);
        cout << foo << " ";
    }
    cout << endl;
}

(col - hw) が負の場所で、配列の半分の foo の値が台無しになります。col は int で最初に来るので、式のこの部分が int に変換されて負になると考えました。残念ながら、そうではないようです。符号なしの値のオーバーフローが発生し、その理由がわかりません。

この問題を解決するにはどうすればよいですか? 式の全体または一部にキャストを使用しますか? どのタイプのキャスト (C スタイルまたは static_cast<...>) ですか? キャストの使用にオーバーヘッドはありますか (高速に動作させるにはこれが必要です!)?

編集:すべての unsigned int を通常の整数に変更しましたが、この状況でなぜそのオーバーフローが発生したのか疑問に思っています。

4

5 に答える 5

7

符号なし整数は、符号なし演算を実装します。符号なし算術はモジュロ算術です。すべての値はモジュロ 2^N で調整されます。ここで、N は符号なし型の値表現のビット数です。

簡単に言えば、符号なし算術演算は常に非負の値を生成します。式が負の値になるたびに、値は実際には 2^N を「ラップ」して正になります。

[sub-]式で符号付き整数と符号なし整数を混在させると、符号なし算術演算が「勝ち」ます。つまり、計算は符号なしドメインで実行されます。たとえば、 を実行するとcol - hw、 と解釈され(unsigned) col - hwます。これは、 forcol == 0hs == 31you が-31結果として得られないことを意味します。代わりにUINT_MAX - 31 + 1、通常は非常に大きな正の値である を取得します。

そうは言っても、私の意見では、符号なしの型を使用して本質的に非負の値を表すことは常に良い考えであることに注意する必要があります。実際には、C/C++ の整数変数のほとんど (または少なくとも半分) は、プログラムに符号なしの型を持たせる必要があります。例で署名されていない型を使用しようとする試みは十分に正当化されます (意図を正しく理解していれば)。さらに、私はunsignedforcolrow同じように。ただし、(前述のように) 符号なし算術演算が機能する方法を念頭に置き、それに応じて式を記述する必要があります。ほとんどの場合、式は符号なしの範囲を超えないように書き換えることができます。つまり、ほとんどの場合、明示的に符号付きの型にキャストする必要はありません。それ以外の場合、最終的に負の値を使用する必要がある場合は、符号付き型へのキャストを適切に配置することで問題を解決できます。

于 2010-05-17T17:18:24.737 に答える
2

heightwidth、およびhwsigned intを作成するのはどうですか? それらを無署名にすることで、実際に何を得ていますか?符号付き整数と符号なし整数を混在させると、常に問題が発生します。少なくとも一見したところ、ここで符号なしの値を使用しても何も得られないように見えます。したがって、それらすべてに署名を付けて、問題を回避することもできます。

于 2010-05-17T17:09:07.727 に答える
1

変換規則は逆です。同じ型の符号付きバージョンと符号なしバージョンを混在させると、符号付きオペランドは符号なしに変換されます。

于 2010-05-17T17:19:09.090 に答える
0

これを高速にしたい場合は、ループを開始する前にすべての unsigned 値を static_cast し、unsigned int ではなく int バージョンを使用する必要があります。入力が署名されていないことを引き続き要求し、アルゴリズムの途中でそれらをキャストして、関数に必要なドメインを保持することができます。

于 2010-05-17T17:10:48.920 に答える
0

キャストは自動的には行われません。キャストされていない算術演算にはまだ用途があります。通常の例は int / int = int であり、float に変換しないことでデータが失われる場合でも同様です。INT_MAX が小さすぎるために不可能でない限り、signed int を使用します。

于 2010-05-17T17:20:49.790 に答える