符号あり右シフト

符号あり整数の右シフト動作は一定していません。
まず正の数の右シフトは左から0がシフトインされます。
負の数の場合は、ANSI Cでは規定していません。
処理系に依存するという事になっています。
その動作には2種類あります。


(1)符号ビットのコピーをシフトインする(算術シフト)
(2)0をシフトインする(論理シフト)


算術シフトは、算術計算に耐えるシフトを意味しています。
例えば-1000を右1ビットシフトしたら-500になるべきだというシフトです。
これに対して論理シフトは、
とにかく指定数だけシフトすればいいというシフトです。
負の数を右にシフトして、結果が正の数になっても構わないというものです。

このように右シフトには2つの方法がありますが、
実際には算術シフトをとっている処理系が大部分です。
それはシフト演算と算術演算とに一貫性がでてくるからです。
このようにシフト演算には処理系依存という要素がありますから
実際の運用にあたっては、
シフト処理は符号無し整数に対して行う
という姿勢が望ましいと言えます。
C > 演算 | comments (0) | trackbacks (0)

シフト演算


#include <stdio.h>
void main()
{
 int b = 1;
 printf( "%d %d\n", b * 2, b << 1 );
 printf( "%d %d\n", b * 4, b << 2 );
 printf( "%d %d\n", b * 8, b << 3 );
 printf( "%d %d\n", b * 16, b << 4 );

 int a = 16;
 printf( "%d %d\n", a / 2, a >> 1 );
 printf( "%d %d\n", a / 4, a >> 2 );
 printf( "%d %d\n", a / 8, a >> 3 );
 printf( "%d %d\n", a / 16, a >> 4 );
}


実行結果

2 2
4 4
8 8
16 16

8 8
4 4
2 2
1 1


シフト対象整数が正の時、
i * 2n と i << n は同じ結果になる。
i / 2n と i >> n は同じ結果になる。

左に1ビットシフトするごとに値は2倍になる
右に1ビットシフトするごとに値は1/2倍になる
C > 演算 | comments (0) | trackbacks (0)

算術変換と整数の昇格

算術変換
2項演算子に異なる型のオペランドを指定した場合、「精度の高い」ほうに型を揃えてから演算が行われる。
制度の高い順に
long double>double>float>unsigned long>long>unsigned int>int
となる。
※longとunsigned intの場合はunsigned longになる。

整数の昇格
int型よりもサイズの小さい整数は、演算の前に無条件に符号付int型に変換される。

原則

・ビットフラグなど、ビット単位の情報が重要なものは
符号無し整数にする。
・配列の要素数が多いなど、サイズが重要な場合には
できるだけ小さいデータ型にする。
・さもなければint


何かの個数や人の年齢といった値は負になる事が無い為、符号無し整数にしたくなるかも知れません。
しかし、こうした変数はintにしておく事で、余計な型変換を防ぐ事ができます。
また、charやshortを使用すると、整数の昇格によって余計な変換が発生する分だけ遅くなります。
C > 演算 | comments (0) | trackbacks (0)

and演算での剰余演算


#include <stdio.h>
void main()
{
 int i;
 for ( i=0; i<16; i++ ) printf( "%d ", i % 2 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i & 1 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i % 4 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i & 3 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i % 8 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i & 7 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i % 16 );
 printf( "\n" );
 for ( i=0; i<16; i++ ) printf( "%d ", i & 15 );
 printf( "\n" );
}


実行結果

0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15


i % (n2) は i & (n2-1) と同じである。
C > 演算 | comments (0) | trackbacks (0)

論理演算子

論理和
A||B

論理積
A&&B

否定
!A

排他的論理和
(A||B)&&!(A&&B)


・優先順位は!&&||となります。
&&||は左から右に評価されることが保証されています。
 そして条件が一致すれば、そこで条件判定を中止します。
 ですから合致する確率の高い条件を最初に記述した方が処理効率が良くなります。
C > 演算 | comments (0) | trackbacks (0)

ビット演算

ビットパターンを表示するサンプル

#include <stdio.h>
void bitpat( int x )
{
 int i;
 for ( i = 31; i>=0; i-- )
  printf( "%d", ( x >> i ) & 0x00000001 );
 printf( "\n" );
}

void main()
{
 int a;
 while ( scanf( "%d", &a ) != EOF )
  bitpat( a );
}

C > 演算 | comments (0) | trackbacks (0)

演算子の優先順位

優先順位123456789101112131415
関数、かっこ()              
配列[]              
構造体.、->              
 sizeof             
ポインタ *、&             
インクリメント・ディクリメント ++、--             
算術 -*、/、%+、-           
関係     <、<=、>、>===、!=        
ビット ~  <<、>>  &^|     
論理 !        &&||   
条件            ?:  
代入             =、+=、*=、etc 
カンマ              ,
C > 演算 | comments (0) | trackbacks (0)