hantas's blog

ブログ移転しました→ http://blog.taniho.net/

整数型の変数について

この記事は新入生向けに噛み砕いて説明をします。 内容的には基本情報技術者試験の「基礎理論-離散数学」レベルの知識にC言語の知識をプラスした程度となります。
2進数・10進数・16進数の理解,演算,正負の付け方,またC言語における変数の型の話をまとめています。

はじめに

2進数,16進数などの言葉を聞いたことがある人は多いかと思います。 なぜこれらの表記法があるのでしょうか?

羊がたくさんいるとき,私達は「1匹,2匹,3匹,4匹,5匹。」と数えます。
同じ数の羊をコンピュータは「1,10,11,100,101」と数えます。
同じものを数えていますが,その表記法が違うだけです。

コンピュータは基本的にデジタル回路です。値の読み書きは,0と1しかありません。 私達が使っている10進数の数字を理解することができないのです。 そのため,コンピュータが扱える0と1だけで数字を表す2進数という表現方法が用いられるようになりました。
プログラムの理解には2進数の理解が必須です。 また,2進数をわかりやすくするためによく用いられる16進数も覚えておくと良いでしょう。

これからの記事を読むにあたって,ひとつだけ注意点です。
例えば”1010”と書かれたときに,これは10進数の1010なのか,2進数(10進数に直すと10)なのか,16進数(10進数に直すと4112)なのか区別がつきません。 そこで,一般的に用いられている表記法を用います。

  • 10進数の場合はそのまま書く:1010
  • 2進数の場合は頭に”0b”とつける:0b1010
  • 16進数の場合は頭に"0x"とつける:0x1010

n進数

まずはn進数<->n進数の相互変換ができるようになりましょう。 これは基礎中の基礎なので確実にできるようにしておいてください。

基数

「基数」というと何なのかよくわかりませんが,実は毎日使っています。

「さんまん せん よんひゃく じゅう ご (31415)」

この赤文字が「基数」です。 あえて数式を分解するなら次のような感じです。

104 + 1×103 + 4×102 + 1×101 + 5×100 = 31415

このように,10進数の場合は基数が100,101,102,103,104,……と順に続いていきます。 基数が10のn乗なので,10進数というわけです。

同じように考えて,2進数の場合は基数が20,21,22,23,24,……と続いていくはずです。

したがって,10進数の31415を2進数で表現すると,次の式から0111101010110111となります。

1×214 + 1×213 + 1×212 + 1×211 + 1×29 + 1×27 + 1×25 + 1×24 + 1×22 + 1×21 + 1×20 = 0b0111101010110111

16進数の場合は,160,161,162,163,164,……と続きます。

同様に,10進数の31415を2進数で表現すると,次式から7AB7となります(ただし,Aは10進数で10,Bは10進数で11を意味します)。

7×163 + A×162 + B×161 + 7×160 = 0x7AB7

変換

※この表は後で使います

2進数 16進数 10進数(参考)
0000 0 0
0001 1 1
0010 2 2
0011 3 3
0100 4 4
0101 5 5
0110 6 6
0111 7 7
1000 8 8
1001 9 9
1010 A 10
1011 B 11
1100 C 12
1101 D 13
1110 E 14
1111 F 15
10000 10 16
  1. 2進 -> 10進
    先ほど説明した基数の考え方を使います。
    LSB(一番右に示される桁)から順番に2のn乗をかけながら,足しあわせていきます。
    例:0b10011010
    1×27 + 1×24 + 1×23 + 1×21 = 154
  2. 2進 -> 16進
    一番簡単です。 これは基数もクソもありません。覚えゲーです。 実は2進数の4桁と16進数の1桁はちょうど一対一で対応しています。 2進数と16進数は桁の繰り上げが起こるタイミングが一致していることを確認してください。
    あわせて,上に示した表は丸暗記してください。 例:0b10011010
    1. 2進数を4桁ずつ分離します
      1001 1010
    2. 表にしたがって16進数に直します
      9 A
    3. くっつけます
      0x9A
  3. 10進 -> 2進
    2の0〜16乗まですべて覚えましょう。 それの足し合わせで2進数表記できるので,頑張ってください。
    (真面目に変換したい人は各自調べてみてください)
  4. 16進 -> 2進
    さっきの逆です。
    例:0xE5
    1. 1桁ずつに分けます
      E 5
    2. 対応表に基づいて変換します
      1110 0101
    3. くっつけます
      0b11100101

演算

次は二進数の演算について軽く触れていきましょう。

加算

加算はとても簡単です。 小学校で習った筆算と同じことをすればできます。 ただし1+1の計算で繰り上がりが発生することだけ注意してください。
例:0b00001010+0b00111100

f:id:hantas:20160310000938p:plain

減算

では減算はどうすればいいでしょうか。
例えば0b0001-0b0010は幾つになるでしょうか……? -0001? 1111?

2の補数

2進数の世界にはマイナスの記号は存在しません。 そのかわり,負の数を2進数で表現したい場合は「2の補数」という技を使います。

ここでは8ビットの2進数があるとします。
”00000000”
では2の補数を使って,”−11”を表現してみましょう。

  1. まずは絶対値を二進数で表記
    11を二進数で表記します。
    0b00001011
  2. ビットをすべて反転
    0b11110100
  3. 1加算する
    0b11110101

できました。-11は0b11110101として表記することができます。

2の補数で表された2進数を10進数に戻すときは,逆順に,1減算した後にビットを反転すれば,10進数の絶対値を得ることができます。

減算

2の補数とは,単なる負数の表現法というわけではありません。
2の補数で表現された2進数を「加算」することによって,減算の計算をすることができるのです。
例:20-31を2進数で計算
20は,2進数で0b00010100
31は,2進数で0b00011111
-31は,2進数で0b11100001

f:id:hantas:20160310010047p:plain

というわけで-11という解が出てきました。

C言語における整数型

さて,2進数で整数を扱う基礎は以上となります。 これらの基礎を学んだ上で,C言語にはどのように使われているか,少しだけ考えてみましょう。

符号長

変数の型はいくつかありました。

char, short, long, long long, そして忌々しきint

符号長を表にまとめておきます。 要は使うことのできる2進数の桁数です。

符号長
char 8bit
short 16bit
long 32bit
long long 64bit
int 処理系依存(近年のコンピュータは32bit)

最大値・最小値

ここまで勉強してきた内容から,変数の最大値と最小値を算出することができるはずです。
signedとunsigned,それぞれ考えてみましょう。

自力で考えてみたほうが理解が深まります。

unsigned

すべての桁を”1”にすれば最大値が出ます。 最小値は0です。

signed

正数で一番大きな数は,MSBが0,それ以外が1の場合です。

負数で一番小さな数は,MSBが1,それ以外が0の場合です。

ここでまとめる必要もないので

既にまとめているサイトが多数あるので引用します。 自分の考えがあっていたか確認してみてください。 色々なデータ型の最大値・最小値 - miyapongの日記(仮)

型名をわかりやすくする

正直,charとかlonglongだとか言われても何ビットかパット見でわかりません。
また,”char”はsignedなのかunsignedなのか,コンパイルオプションを見ないとわからないのです(デフォルトでunsignedとしている開発環境が多い)

そこで,C標準ライブラリに"stdint.h"というライブラリがあります。 こいつを使うことで変数のサイズがひと目でわかるようになります。

標準の型 新たに定義された型
signed char int8_t
unsigned char uint8_t
signed short int16_t
unsigned short uint16_t
signed long int32_t
unsigned long uint32_t
signed long long int64_t
unsigned long long uint64_t

他にも幾つかの型が宣言されています。 便利なのでこちらを使うことを推奨します。

おわりに

Winプログラムではなく,マイコン向けのプログラムを書くのにビット列の扱い方を教えないのはあまりに無茶だと思います。
せめて2進数の整数についてはこれくらいの知識を持って今後の製作に励んでもらいたいと思います。
また,興味のある人は是非「基本情報技術者試験」や「応用情報技術者試験」などの資格にチャレンジしてもらいたいと思っています。
テクノロジやマネジメントについて,幅広い分野をかじることができるのできっと楽しいと思います。

(多分)浮動小数点型の基礎に続く

参考: 2016年、C言語はどう書くべきか (前編) | プログラミング | POSTD