|  パソコン活用研究C&C++究め道 Unsigned型と浮動小数点型の内部構造
 変数のデータ型についての話は、一番おもしろくないものだと思いますが、画面出力&キーボード入力&変数のところでは、データ型についてこまいかいことはふれなかったので、unsighned型と浮動小数点型(実数型)などについて少し補足しておきたいと思います。
 1 unsigned型コンピュータは2進数で数値を扱っていますが、負の数はどうやって表すのでしょうか。整数型(short,
      int, long)および文字型(char)には符号付と符号無し(unsigned型)のふたつのパターンがあります。符号無しの場合は、表現できるのは正の数だけで、負の数を表すことができません。他方、符号付の場合は、データの最上位ビットを符号用に使い、負(マイナス)も表現できるようにしています。
 
 char型とshort型の一般的な例を以下に示します。
 
 char型
 符号なし(unsigned型)
 
        
          表現できる値
            | ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |  
            | 内部構造 | <--データ  --> |  &H00 〜 &HFF
 0   〜  255
 00000000 〜 11111111
 
 符号付
 
        
          表現できる値
            | ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |  
            | 内部構造 | 符号 0 正
 1 負
 | <--データ --> |  &H00   〜   &H7F    &H80   〜   &HFF
 0      〜   127     -128   〜   -1
 00000000 〜 01111111  10000000 〜 11111111
 
 
 short型
 符号なし
 
 
        
          表現できる値
            | ビット | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |  
            | 内部構造 | <----    データ           -----> |  &H0000 〜 &HFFFF
 0     〜 65535
 
 符号あり
 
 
        
          表現できる値
            | ビット | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |  
            | 内部構造 | 符号 0 正
 1 負
 | <----    データ           -----> |  &H0000 〜 &HfFFF &H8000 〜 &HFFFF
 0     〜 32767  -32768 〜 -1
 
 
 コンピュータ上で負の数を表す方法にはいくつかあり、ここで説明したのは2の補数方式
 という方法です。2の補数方式について、負の数の表し方(インターネット&PC120%活用)で
 説明しています。
 
 
 実際のプログラムによる符号付き型と符号なし型の挙動の違いは
 Unsigned型(符号なし型)と符号付き型のテストを参照下さい。
 
 
 
 
 2 浮動小数点型
 浮動小数点型(実数型)の場合は、一般的には符号付型のみになります。浮動小数点の内部構造の仕様にはいくつかバリエーションがありますが、基本は同じです。ここでは、LSIC86に実装されている浮動小数点型で説明してみます。
 LSIC86のマニュアルから浮動小数点型の説明の部分を抜粋してみます。
 
 (マニュアルからの抜粋)
 
 浮動小数点型は、 上位から順に符号ビット、指数部、仮数部の3つのフィールドから構成され、その各ビット数は、上の表中にしるされているとおりです。符号ビットはどの型も1ビットで、0のときは正、1のときは負を表します。 指数部はげたをはいており (biased)、0111...111というビットパターンが指数部0を意味します。仮数部は、float型とdouble型では、先頭の1を省いたケチ表現で、小数点は一番左にあるものとみなされます。long double型では、先頭の1は省略されず、小数点はbit63とbit62の間にあるものとみなされます。以下に、いくつかの浮動小数点数について各型での内部表現を 16 進数で示します。
 
              float        double         long double0     00000000 
0000000000000000 
00000000000000000000
 1     3F800000 
3FF0000000000000 
3FFF8000000000000000
 3     40400000 
4008000000000000 
4000C000000000000000
 -3     C0400000 
C008000000000000 
C000C000000000000000
 0.25  3E800000 
3FD0000000000000 
3FFD8000000000000000
 
 
 マニュアルに書いてあることは、浮動小数点について理解している人でないと、何のことかわからないと思いますので、わかりやすく説明してみます。
 LSIC86の場合、float型は、以下のように符号を表す最上位ビットに、指数部8ビット、仮数部23ビットの構成をとります。(指数部、仮数部をどう扱うかは、浮動小数点のバリエーションにより異なるので、他のコンパイラでは少し異なるかもしれません。ただし、基本は同じ)
 
        
          
            | ビット | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | ............. | 4 | 3 | 2 | 1 | 0 |  
            | 内部構造 | 符号 0 正
 1 負
 | 指数部 | 仮数部 |  先頭に、1. がつくと仮定して、指数部と仮数部は以下のような役割となって実数を表現します。
 ±1. [仮数分]×2[指数部]
 
 更に細かくみると、LSIC86では、指数部は7F(16進)の時に0を意味するので、正確には
 ±1. [仮数分]×2[指数部-7F]
 ということになります。
 
 仮数部は、
 第22ビットが、1/2 = 0.5
 第21ビットが、1/4 = 0.25
 第20ビットが、1/8 = 0.125
 を意味します。
 
 上記のマニュアルで、1は内部表現で3F800000(16進)になっていますが、どうしてこれが1になるか検証してみましょう。3F800000を2進になすと、以下の通りになります。
 
        
          
            | 3 | F | 8 | 0 | 0 | 0 | 0 | 0 |  
            | 0011 | 1111 | 1000 | 0000 | 0000 | 0000 | 0000 | 0000 |  これを、符号と指数部、仮数部に分解して分析してみます。 
        
          
            | ビット | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | ............. | 4 | 3 | 2 | 1 | 0 |  
            | 内部構造 | 符号 0 正
 1 負
 | 指数部 | 仮数部 |  
            |  | 0 | 01111111(&H7F) | 00000..... 0000000000000000(&H0) |  符号は0なので正の数。指数部は7Fですが、LSICでは7F-7F = 0になります。仮数部は0です、よって
 1. [0]×2[0]  = 1.0 × 1 = 1.0
 ということになります。
 
 では、もうひとつfloatの内部表現C0400000が-3になるかも検証してみましょう。まず2進に変換してみます。
 
        
          
            | C | 0 | 4 | 0 | 0 | 0 | 0 | 0 |  
            | 1100 | 0000 | 0100 | 0000 | 0000 | 0000 | 0000 | 0000 |  符号、指数部、仮数部に分解します。
 
 
        
          
            | ビット | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | ............. | 4 | 3 | 2 | 1 | 0 |  
            | 内部構造 | 符号 0 正
 1 負
 | 指数部 | 仮数部 |  
            |  | 1 | 10000000(&H80) | 10000..... 0000000000000000 |  符号は1 よって負の数
 指数部はLSICでは80-7F = 1
 仮数部は0.5
 -1. [0.5]×2[1] = -1.5 × 2 = -3.0
 
 では、実数の内部表現を2進数で表すプログラムを作成して、いくつかの実数の内部表現を確かめてみましょう。
 以下のプログラムは、シフト演算で、内部表現の各ビットをとりだし表示します。なお、float型(実数型)にはシフト演算が使えないので、short型2個からなるs_tag型を作り、float型と共用体を作ることにより、内部表現を取り出しています。
 シフト演算については演算子を、共用体については共用体をご参照下さい。
 
        
          
            | #include<stdio.h> 
 struct s_tag {
 short s1;
 short s2;
 };
 
 union u_tag {
 struct s_tag  s_acc;
 float f;
 } u_acc;
 
 main()
 {
 int i, bit;
 scanf("%f",&u_acc.f);
 printf("\n");
 for (i=15;i>=0;i--){
 bit=(u_acc.s_acc.s2>>i)&0x01;
 printf("%1d",bit);
 }
 for (i=15;i>=0;i--){
 bit=(u_acc.s_acc.s1>>i)&0x01;
 printf("%1d",bit);
 }
 
 printf("\n");
 }
 
 |  以下、実行例です。確かめてみて下さい。 
        
          
            | D:\win95\C>float 1.0
 
 00111111100000000000000000000000
 
 D:\win95\C>float
 1.0000001
 
 00111111100000000000000000000001
 
 D:\win95\C>float
 1.0000002
 
 00111111100000000000000000000010
 
 D:\win95\C>float
 1.000001
 
 00111111100000000000000000001000
 
 D:\win95\C>float
 1.00001
 
 00111111100000000000000001010100
 
 D:\win95\C>float
 1.5
 
 00111111110000000000000000000000
 
 D:\win95\C>float
 3.0
 
 01000000010000000000000000000000
 
 D:\win95\C>
 
 |  浮動小数点のもう少し立ち入った説明は、パソコン活用研究PCマニアック道のカセットインターフェースによるデータ通信でも書いています。こちらはBASICの話ですが基本は同じですので参照してみて下さい。
 TopPage
 
 |