ホームに戻る
 浮動小数のメモリ上の扱いについて

 まず2進数のおさらい、

2進数は数字の0と1のみで表現する。
0から1ずつ増える場合、0、1、10、11、100・・・と増える。
この場合10進数の2が2進数の10にあたり、
10進数の3は2進数の11、10進数の4は2進数の100にあたる。
10進数の場合は一桁上げるのに10倍するが、
2進数の場合は一桁上げるのに2倍すればよいことになる。
これは一桁下げるには2で割ればよいという考えによる。
すなわち、10進数の0.5は2進数の0.1であり、
10進数の0.25は2進数の0.01であり、
10進数の0.125は2進数の0.001である。

 ここから浮動小数について

まず浮動小数というと32ビットの値で、
先頭の1ビットが正か負かのフラグ(0=正、1=負)。
次の8ビットが2^(E−127)のEの値(符号無しの正の値)。
残り23ビットが1.****の「****」部分となります。

これではわけがわからないので例として、
小数の値である「8.75」を浮動小数に変換してみます。

まず整数部分の「8」は2進数で「1000」。
小数部分は「0.5」が2進数で「0.1」、
「0.25」が2進数で「0.01」であるので、
「0.75」は「0.11」ということになります。
すなわち、「8.75」は2進数で「1000.11」となります。

これを無理やり「1.****」の形に変換します。
すなわち、「1.00011 × 2^3」となります。

ここまできたらあとは簡単で、

正か負か?→正なので先頭の1ビットは「0」。
E−127=3→よってE=「130」。
1.****=1.00011→よって「00011」。

ゆえに「8.75」は、

「0 10000010 00011000000000000000000」

と変換されます。

この浮動小数の規格をIEEE754(1985)というそうです。
浮動小数の足し算や引き算はEの値が大きいほうにあわせて計算されるので、
ここで丸め誤差に加えて情報落ちや桁落ちが発生します。

以下に確認用プログラムを用意しました。

/*
*   浮動小数(32ビット値)を 0 と 1 に変換して表示します
*/

#include 

#define BYTE_SIZE 8    /* 1バイトの幅 */
#define RETURN_COLS 8  /* 表示する列数 */

typedef union{
  float f;
  char c[4];
}floatchar;

/* char型の文字を 0 と 1 で出力 */
void print_byte_string(char c);

/* 画面に出力 */
void (*disp)(float);
void disp_le(float);
void disp_be(float);

int main(void)
{
  short a = 1;

  if(*(char *)&a == 1){
    /* リトルエンディアンのとき */
    disp = disp_le;
  }
  else{
    /* ビッグエンディアンのとき */
    disp = disp_be;
  }

  disp(1.5);
  disp(1.25);
  disp(1.75);
  disp(1.875);

  return 0;
}

/*
* 画面への出力(リトルエンディアン)
*/
void disp_le(float f)
{
  int i;
  floatchar fc;

  fc.f = f;

  printf("%f", f);

  putchar(':');

  for(i = 3; i >= 0; i--)
  {
    putchar(' ');
    print_byte_string(fc.c[i]);
  }

  putchar('\n');

  return;
}

/*
* 画面への出力(ビッグエンディアン)
*/
void disp_be(float f)
{
  int i;
  floatchar fc;

  fc.f = f;

  printf("%f", f);

  putchar(':');

  for(i = 0; i <= 3; i++)
  {
    putchar(' ');
    print_byte_string(fc.c[i]);
  }

  putchar('\n');

  return;
}

/*
* char型の8ビットを 0 と1で出力
*/
void print_byte_string(char c)
{
  int i;

  for(i = BYTE_SIZE - 1; i >= 0; i--)
  {
    if(((c >> i) & 1) == 1) /* ビットが 0 か 1 か? */
      putchar('1');
    else
      putchar('0');
  }
}

inserted by FC2 system