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
留言列表