http://graphics.stanford.edu/~seander/bithacks.html から分岐せずに整数の絶対値(abs)を計算するためのコードを引用
int v; // we want to find the absolute value of v
unsigned int r; // the result goes here
int const mask = v >> sizeof(int) * CHAR_BIT - 1;
r = (v + mask) ^ mask;
特許取得済みのバリエーション:
r = (v ^ mask) - mask;
とは CHAR_BIT
そして、どのようにそれを使用しますか?
このコードは、符号付き型での右ビットシフトの実装定義の動作に依存することに注意してください。 gccは常に正常な動作(sign-bit-extension)を提供することを約束しますが、ISO Cでは実装で上位ビットをゼロで埋めることができます。
この問題を回避する1つの方法:
#ifdef HAVE_SIGN_EXTENDING_BITSHIFT
int const mask = v >> sizeof(int) * CHAR_BIT - 1;
#else
int const mask = -((unsigned)v >> sizeof(int) * CHAR_BIT - 1);
#endif
Makefile
またはconfig.h
などは、プラットフォームに応じてビルド時にHAVE_SIGN_EXTENDING_BITSHIFT
を定義できます。
CHAR_BIT
は、char
のビット数です。最近では、ほとんどすべてのアーキテクチャが1バイトあたり8ビットを使用していますが、常にそうではありません。一部の古いマシンでは、以前は7ビットバイトを使用していました。
<limits.h>
にあります。
元の質問の明示的な質問(CHAR_BITとは何か)と暗黙的な質問(この仕組み)の両方に答えようとしています。
CおよびC++のcharは、Cプログラムがアドレス指定できるメモリの最小単位を表します*
CおよびC++のCHAR_BITは、charのビット数を表します。 char型の他の要件により、少なくとも8でなければなりません。実際には、現代のすべての汎用コンピューターでは正確に8ですが、一部の歴史的または専門的なシステムはより高い価値を持っている場合があります。
JavaにはCHAR_BITやsizeofに相当するものがありません。Javaのすべてのプリミティブ型は固定サイズであり、オブジェクトの内部構造はプログラマーにとって不透明です。このコードをJava「sizeof(int)* CHAR_BIT-1」を単純に固定値31に置き換えることができます。
この特定のコードでは、intのビット数を計算するために使用されています。この計算では、int型にパディングビットが含まれていないことを前提としていることに注意してください。
コンパイラが符号付き数値のビットシフトで符号拡張を選択し、システムが負の数値に2の補数表現を使用すると仮定すると、これは「MASK」が正またはゼロの値に対して0、負の値に対して-1になることを意味します。
2の補数を否定するには、ビットごとの否定を実行してから1を追加する必要があります。同様に、1を減算してからビット単位で否定することもできます。
再び2の補数表現を想定すると、-1はすべて1で表されるため、排他的または-1を使用すると、ビットごとの否定と同等になります。
したがって、vが0の場合、数値はそのままで、vが1の場合は無効になります。
注意すべきことは、CおよびC++での符号付きオーバーフローは未定義の動作であるということです。したがって、このABS実装を最も負の値に使用すると、未定義の動作が発生します。これは、プログラムの最終行がunsigned intで評価されるようにキャストを追加することで修正できます。
*通常、ハードウェアがアドレス指定できるメモリの最小単位と同じではありますが、そうではありません。実装では、ハードウェアアドレス可能メモリの複数のユニットをプログラムアドレス可能メモリの1つのユニットに結合したり、ハードウェアアドレス可能メモリの1つのユニットをプログラムアドレス可能なメモリの複数のユニットに分割したりできます。