Hatena::ブログ(Diary)

憂鬱なプログラマの形而上学 RSSフィード

2011-03-09

浮動小数点数のビット列

浮動小数点数のビット列を解析する必要があったのでついでに解析プログラムを作ってみた。

以下のようにして使う。

# コンパイル
$ gcc ./fl.c -o fl

# 解析
$ ./f 3.402823e+37
* 受け取った数(文字列表現)  :3.402823e+37
* 受け取った数(float型表現) :34028229593250485068252812361638871040.000000
* 受け取った数(double型表現):34028229999999999496011500909022412800.000000
--------------------------------------------------------------------
* float
値        :34028229593250485068252812361638871040.000000
ビット    :01111101110011001100110011001010

符号部    :+1         (1bit:0)
指数部    :124        (8bit:11111011)
仮数部    :1.5033162  (23bit:10011001100110011001010)

指数表現  :3.402823e+37
計算式    :+1 * 1.5033162 * 2の124乗
--------------------------------------------------------------------
* double
値        :34028229999999999496011500909022412800.000000
ビット    :0100011110111001100110011001100101000101001000100100011101010000

符号部    :+1                 (1bit:0)
指数部    :124                (11bit:10001111011)
仮数部    :1.2702158359316304 (52bit:1001100110011001100101000101001000100100011101010000)

指数表現  :3.402823e+37
計算式    :+1 * 1.2702158359316304 * 2の124乗
--------------------------------------------------------------------

以下、プログラム

#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <stdint.h>

#define float_t     float
#define float_size  (sizeof(float_t) * 8)
#define double_t    double
#define double_size (sizeof(double_t) * 8)

#define formatstr_basic \
  "* 受け取った数(文字列表現)  :%s\n" \
  "* 受け取った数(float型表現) :%f\n" \
  "* 受け取った数(double型表現):%f\n" 

#define formatstr_float    \
  ( \
  "* float\n" \
  "値        :%f\n" \
  "ビット    :%s\n" \
  "\n" \
  "符号部    :%-8s   (1bit:%s)\n"  \
  "指数部    :%-8d   (8bit:%s)\n"  \
  "仮数部    :1.%-8llu (23bit:%s)\n" \
  "\n" \
  "指数表現  :%e\n" \
  "計算式    :%s * 1.%llu * 2の%d\n" \
  )
  
#define formatstr_double    \
  ( \
  "* double\n" \
  "値        :%f\n" \
  "ビット    :%s\n" \
  "\n" \
  "符号部    :%-16s   (1bit:%s)\n"  \
  "指数部    :%-16d   (11bit:%s)\n"  \
  "仮数部    :1.%-16llu (52bit:%s)\n" \
  "\n" \
  "指数表現  :%e\n" \
  "計算式    :%s * 1.%llu * 2の%d\n" \
  )
  
#define str_separator "--------------------------------------------------------------------"

union ufloat {
  uint32_t i;
  float_t f;
};

union udouble {
  uint64_t i;
  double_t f;
} ;

/* === util */
void usage(char *scriptname) {
  printf("usage : %s <number>\n" , scriptname);
}
#define show_error(a) fprintf a

/* === parse_double */
void parse_double(uint8_t **s , uint64_t x) {
  int i ;
  uint8_t *s0 = *s;
  for (i=double_size-1; i >= 0 ; i--) {
    s0[i] = (uint8_t)(x & 1);
    x >>= 1;
  }
}
/* === parse_float */
void parse_float(uint8_t **s , uint32_t x) {
  int i ;
  uint8_t *s0 = *s;
  for (i=float_size-1; i >= 0 ; i--) {
    s0[i] = (uint8_t)(x & 1);
    x >>= 1;
  }
}
/* === alloc_bitstr */
char* alloc_bitstr(uint8_t *s , int size) {
  int i ;
  
  char *s0 = (char*)malloc( sizeof(char) * (size + 1) );
  for (i=0;i<size;i++) 
    s0[i] = (s[i] ? '1' : '0');
  s0[size] = '\0';
  
  return s0;
}  
/* === bit2uint16 */
int16_t bit2uint16(char *bitstr) {
  char c0;
  int16_t i = 0;
  while(c0 = *(bitstr++)) {
    i <<= 1;
    if (c0 == '1') 
      i++;
  }
  return i;
}
/* === bit2uint64 */
uint64_t bit2uint64(char *bitstr) {
  char c0;
  uint64_t i = 0;
  while(c0 = *(bitstr++)) {
    i <<= 1;
    if (c0 == '1') 
      i++;
  }
  return i;
}

/* === main */
int main(int argc, char *argv[] ) {
  union ufloat uf;
  union udouble ud;
  uint8_t *s;
  int i;
  char 
    *bitstr,
    *sign_s , *sign_b ,
    *expo_b, 
    *mantissa_b ;
  int16_t 
    expo;
  uint64_t 
    mantissa;
  
  if (argc != 2) {
    usage(  argv[0] );
    return(-1);
  }
  if ((uf.f = ud.f = atof(argv[1])) == 0) {
    show_error((stderr,"値の解析に失敗しました:%s\n", argv[1]));
    return(-1);
  }
  /* basic */
  printf(formatstr_basic , argv[1] , uf.f , ud.f);
  puts(str_separator);
  
  /* float  */
  s = (uint8_t*)malloc( sizeof(uint8_t) * float_size);
  parse_float(&s , uf.i);
  
  bitstr = alloc_bitstr(s, float_size);
  
  sign_b = alloc_bitstr(s, 1);
  sign_s = (sign_b[0] == '1') ? "-1" : "+1";
  
  expo_b = alloc_bitstr(s + 1, 8);
  expo = bit2uint16(expo_b) - 127;
  
  mantissa_b = alloc_bitstr(s + 9, 23);
  mantissa = bit2uint64(mantissa_b);
  
  printf( formatstr_float , 
          uf.f, bitstr, 
          sign_s, sign_b , 
          expo, expo_b , 
          mantissa, mantissa_b , 
          uf.f , 
          sign_s , mantissa, expo );
  puts(str_separator);
  
  free(s);
  free(bitstr);
  free(sign_b);
  free(expo_b);
  free(mantissa_b);
  
  /* double  */
  s = (uint8_t*)malloc( sizeof(uint8_t) * double_size);
  parse_double(&s , ud.i);
  
  bitstr = alloc_bitstr(s, double_size);
  
  sign_b = alloc_bitstr(s, 1);
  sign_s = (sign_b[0] == '1') ? "-1" : "+1";
  
  expo_b = alloc_bitstr(s + 1, 11);
  expo = bit2uint16(expo_b) - 1023;
  
  mantissa_b = alloc_bitstr(s + 12, 52);
  mantissa = bit2uint64(mantissa_b);
  
  printf( formatstr_double , 
          ud.f, bitstr,  
          sign_s, sign_b , 
          expo, expo_b , 
          mantissa, mantissa_b , 
          ud.f , 
          sign_s , mantissa, expo );
  puts(str_separator);
  
  free(s);
  free(bitstr);
  free(sign_b);
  free(expo_b);
  free(mantissa_b);
  
  return 0; 
}

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/k_yamamot/20110309/1299682633