[回目錄]

 

IEEE754 為浮點數運算之標準。

讀者對於 IEEE754 了解是來自中文 wiki 或計算機課程,

裡面提到的標準目前應都是 IEEE 854-1987 標準,

較新的是 IEEE 854-2008標準,但確實一般用到的,

中文 wiki 或計算機課程之敘述應已足夠。

 

這篇文章只會淺述 IEEE754 欄位分配,

只會做到 取出 / 填入 16 進位數值,

還不會說明怎麼依欄位填入數值,或依數值放入欄位,

因,此系列文章之目的之一,就是要把輸入之浮點數,依各欄位分配,

將其 16 進位 / 2 進位值顯示出來。

 

 


 

欄位分配

IEEE754 欄位主要分三個部份,Signed(正負號)、Exponment(指數)、Mantissa(尾數)。

各欄位佔用之 bit 數不盡相同,同時也會使用位元數不同而 bit 數有所不同。目前較常見的是

單精度 (Signle precision) 浮點數 32 bits 與 倍精度 (double precision) 浮點數 64 bits,

正恰與 C 語言 之 float / double 使用 bit 數相同。

較為罕見為半精度 (half precision) 浮點數,使用 16 bits,而四精度 (Quadruple precision)

使用了 128 bits,目前筆者沒看過,也有聽說有 43bits 、80 bits 之浮點數,這些都顯少見,

欄位敘述如下。

 

Half precision (16 bits)

Signed(正負號):佔 1bit,b15

Exponment (指數):佔 5 bits,b14~b10

Mantissa (尾數):佔 10 bits,b9~b0

 

Single precision (32 bits)

Signed (正負號) :佔 1 bit ,b31。

Exponment (指數):佔 8 bits,b30~b23。

Matnissa (尾數):佔 23 bits,b22~b20。

 

Double precision (64 bits)

Signed (正負號) :佔 1 bit ,b63。

Exponment (指數):佔 11 bits,b62~b52。

Matnissa (尾數):佔 52 bits,b51~b0。

 

Quardruple precision ( 128 bits)

Signed (正負號) :佔 1 bit ,b127。

Exponment (指數):佔 17 bits,b126~b110。

Matnissa (尾數):佔 112 bits,b111~b0。

 

 


 

 C 語言取出/設定各欄位之 16 進制值

 

這裡,只實做 flaot / double ,

因目前 C 語言我看不到 Half precision、Quardruple precision 之類的資料形態。

為避免程式碼裡充斥了許多 magic number,先定義出一些 mask、bit,

若屬於 float 資料型態用的,以 FLT 開頭;

若屬於 double 資料型態用的,以 DBL 開頭。

接下來要做的是,對 float / double 取出 IEEE754 的三個欄位,

其中用到了大量之 bitwise 技巧,為使程式碼清晰,不進行優化,

且由於取出來是要直接翻成 16 進位,故資料型態都用 unsigned ,

唯在 double 之 mantissa 部份吃 52 bits,用 unsigned 存不下,

最後比對程式是否正確方式很簡單,

對 x 值做取出 (sign, exponment, mantissa),

再依 (sign, exponment, mantissa) 設給 y,

最後再判介 x 與 y 是否相等即可,

若要再以 16 進位方式顯示各欄位數值,

請再參考 [浮點數] C 語言顯示浮點數 16/2 進位 這篇文章輔助修改,

此處不予實做,demo code 參考如下。

 

程式碼

 

/*******************************************************************/
/*                                                                 */
/*     filename : FloatingField.c                                  */
/*     author   : edison.shih/edisonx                              */
/*     compiler : Visual C++ 2008                                  */
/*     date     : 2011.03.07                                       */
/*                                                                 */
/*         A.L.L.      R.I.G.H.T.S.     R.E.S.E.R.V.E.             */
/*                                                                 */
/*******************************************************************/
#include <stdio.h>

typedef unsigned uint;
typedef unsigned long long ull;
//--------------------------------------------------
#define FLT_SIGN_BITS 1           // float signed     field using bit
#define FLT_EXP_BITS  8           // float exponment  field using bits
#define FLT_MAT_BITS  23          // float mantissa   field using bits

#define FLT_SIGN_MASK 0x80000000U // float signed bit
#define FLT_EXP_MASK  0x7f800000U // float exponment bits
#define FLT_MAT_MASK  0x007fffffU // float mantissa bits

#define DBL_SIGN_BITS 1           // double signed    field using bit
#define DBL_EXP_BITS  11          // double exponment field using bits
#define DBL_MAT_BITS  52          // double mantissa  field using bits

#define DBL_SIGN_MASK 0x8000000000000000ULL
#define DBL_EXP_MASK  0x7ff0000000000000ULL
#define DBL_MAT_MASK  0x000fffffffffffffULL

//--------------------------------------------------
void   Get754Field32(float v, uint* sign, uint* exp, uint* mat);
void   Get754Field64(double v, uint* sign, uint* exp, ull* mat);
float  Set754Field32(uint sign, uint exp, uint mat);
double Set754Field64(uint sign, uint exp, ull  mat);


///////////////////////////////////////////////////////////////////

int main()
{
     float  f = -2.34E4, f2;
     uint f_sign, f_exp, f_mat;

     double d = 1.23456E208, d2;
     uint d_sign, d_exp;
     ull  d_mat;

     Get754Field32(f, &f_sign, &f_exp, &f_mat); //
取得f 欄位
     f2 = Set754Field32(f_sign, f_exp, f_mat);  // 設定f2 欄位
     printf("\nf=%e , f2=%e\n", f, f2);         // 觀查是否一樣

     Get754Field64(d, &d_sign, &d_exp, &d_mat); // 取得d 欄位
     d2 = Set754Field64(d_sign, d_exp, d_mat);  // 設定d2 欄位
     printf("\nd=%e , d2=%e\n", d, d2);         // 觀查是否一樣
     return 0;
}

///////////////////////////////////////////////////////////////////
//--------------------------------------------------
//
將32 位浮點數v , 拆成signed, exp, mat
void Get754Field32(float v, uint* sign, uint* exp, uint* mat)
{
     uint value = *(uint*)&v; // dump
到unsigned
     *sign = (value & FLT_SIGN_MASK) >> (FLT_MAT_BITS + FLT_EXP_BITS);
     *exp  = (value & FLT_EXP_MASK) >> (FLT_MAT_BITS);
     *mat  = (value & FLT_MAT_MASK);
}
//--------------------------------------------------
//
將64 位浮點數v , 拆成signed, exp, mat
void Get754Field64(double v, uint* sign, uint* exp, ull* mat)
{
     ull value = *(ull*)&v;
     *sign = (uint)((value & DBL_SIGN_MASK) >> (DBL_MAT_BITS + DBL_EXP_BITS));
     *exp  = (uint)((value & DBL_EXP_MASK ) >> (DBL_MAT_BITS));
     *mat  =       ( value & DBL_MAT_MASK );
}
//--------------------------------------------------
//
依sign, exp , mat 設32 位元浮點數
float  Set754Field32(uint sign, uint exp, uint mat)
{
     unsigned x;
     x = (sign << (FLT_MAT_BITS + FLT_EXP_BITS) ) |
           (exp  << FLT_MAT_BITS) |
           (mat);
     return *(float*)&x;
}
//--------------------------------------------------
//
依sign, exp , mat 設64 位元浮點數
double Set754Field64(uint sign, uint exp, ull mat)
{
     ull x;
     x = ((ull)sign << (DBL_MAT_BITS + DBL_EXP_BITS) ) |
           ((ull)exp  << DBL_MAT_BITS) |
           (mat);
     return *(double*)&x;
}

 

執行結果

 

f=-2.340000e+004 , f2=-2.340000e+004

d=1.234560e+208 , d2=1.234560e+208

 

[回目錄]

edisonx 發表在 痞客邦 PIXNET 留言(0) 人氣()