浮點(diǎn)數(shù)轉(zhuǎn)二進(jìn)制浮點(diǎn)數(shù)
整數(shù)部分:
- 整數(shù)部分不斷除以2,保存商和余數(shù)侈离。
- 判斷商是否等于0树绩,如果等于0到第3步萨脑,否則回到第1步。
- 將每一步得到的余數(shù)倒序保存饺饭,得到整數(shù)部分的二進(jìn)制表示渤早。
小數(shù)部分:
- 小數(shù)部分不斷乘以2,保存結(jié)果的整數(shù)和小數(shù)瘫俊。
- 判斷結(jié)果的整數(shù)是否等于1鹊杖,如果等于1到第3步悴灵,否則回到第1步。
- 將每一步結(jié)果的所有整數(shù)順序保存骂蓖,就得到小數(shù)的二進(jìn)制表示
例如:浮點(diǎn)數(shù) 4.8125
整數(shù)部分:
4/2 = 2 0
2/2 = 1 0
1/2 = 0 1
所以整數(shù)部分 4 的二進(jìn)制為 100
小數(shù)部分:
0.8125*2 = 1.625 1
0.625*2 = 1.25 1
0.25*2 = 0.5 0
0.5*2 = 1.0 1
所以小數(shù)部分 0.8125 的二進(jìn)制位 1101
將整數(shù)與小數(shù)部分連接起來就是 100.1101
积瞒,即=
再如:浮點(diǎn)數(shù) 0.05
因?yàn)橹挥行?shù)所以只處理小數(shù)部分:
0.05*2 = 0.1 0
0.1*2 = 0.2 0
0.2*2 = 0.4 0
0.4*2 = 0.8 0
0.8*2 = 1.6 1
0.6*2 = 1.2 1
0.2*2 = 0.4 0
0.4*2 = 0.8 0
0.8*2 = 1.6 1
0.6*2 = 1.2 1
0.2*2 = 0.4 0
0.4*2 = 0.8 0
0.8*2 = 1.6 1
...... 無限循環(huán)
所以0.05的二進(jìn)制 = 0.0000 1100 1100 1100 1100 1100 1101 ....
可以看到二進(jìn)制小數(shù)是無法準(zhǔn)確表示浮點(diǎn)數(shù)的,所以就有了精度一說.
單精度浮點(diǎn)數(shù)用32位二進(jìn)制表示如下:
符號(hào)位1位 階碼8位 小數(shù)位23位
雙精度浮點(diǎn)數(shù)用64位二進(jìn)制表示如下:
符號(hào)位1位 階碼11位 小數(shù)位52位
由上可知登下,
單精度浮點(diǎn)數(shù)精度為 pow(2,23) = 8388608 = 0.8388608 x pow(10,7)
所以單精度浮點(diǎn)數(shù)對(duì)應(yīng)的10進(jìn)制精度為 7
位多
雙精度浮點(diǎn)數(shù)精度為 pow(2,52)-1 = 4503599627370496 = 0.4503599627370496 x pow(10,16)
所以雙精度浮點(diǎn)數(shù)對(duì)應(yīng)的10進(jìn)制精度為 16
位多
浮點(diǎn)數(shù)的計(jì)算機(jī)表示 (IEEE754標(biāo)準(zhǔn))
移碼(又叫增碼)是由補(bǔ)碼的符號(hào)位取反得到赡鲜,一般用指數(shù)的移碼減去1來做浮點(diǎn)數(shù)的階碼,
引入的目的是便于浮點(diǎn)數(shù)運(yùn)算時(shí)的對(duì)階操作庐船。為了保證浮點(diǎn)數(shù)的機(jī)器零為全0银酬。
對(duì)于定點(diǎn)整數(shù),計(jì)算機(jī)一般采用補(bǔ)碼的來存儲(chǔ)筐钟。
正整數(shù)的符號(hào)位為 0揩瞪,反碼、補(bǔ)碼篓冲、原碼都一樣李破。
負(fù)整數(shù)的符號(hào)位為 1,原碼壹将、反碼和補(bǔ)碼的表示各不相同嗤攻,
由原碼變成反碼和補(bǔ)碼有如下規(guī)則:
- 原碼符號(hào)位為1不變,整數(shù)的每一位二進(jìn)制數(shù)位取反得到反碼诽俯;
- 反碼符號(hào)位為1不變妇菱,反碼數(shù)值位最低位加1得補(bǔ)碼。
比如暴区,以一個(gè)字節(jié) 8bits 來表示 -3闯团,
那么-3的各種碼,原碼-->反碼-->補(bǔ)碼--->移碼
原碼:[ ? 3 ] = 1 000001 1仙粱,最高位1位符號(hào)位
反碼:[ ? 3 ] = 1 111110 0房交,原碼符號(hào)位不變,其他位取反
補(bǔ)碼:[ ? 3 ] = 1 111110 1伐割,反碼符號(hào)為不變候味,最低位加1
移碼:[ ? 3 ] = 0 111110 1,補(bǔ)碼符號(hào)為取反
浮點(diǎn)數(shù)二進(jìn)制表示:
s:符號(hào)位隔心,0正數(shù)白群,1負(fù)數(shù)
M:小數(shù)部分,使用原碼表示
E:階碼济炎,使用其原碼+127表示或者用其移碼-1表示川抡,
比如十進(jìn)制4.5的單精度浮點(diǎn)數(shù)的二進(jìn)制 = 表示為上述公式則為
看到這里的E
為2
,那么它在計(jì)算機(jī)實(shí)際存儲(chǔ)為 2 + 127 = 129
=
根據(jù)上面的公式各部分表示的規(guī)則得到一個(gè)32位浮點(diǎn)數(shù)表示如下表:
符號(hào)位s:1位 | 階碼E:2~9位 | 小數(shù)位M:10~32位 |
---|---|---|
0 | 2+127=129 | 001 |
0 | 10000001 | 00100000000000000000000 |
符號(hào)位為0
表示是正數(shù),所以4.5
的二進(jìn)制存儲(chǔ)為0 10000001 00100000000000000000000
,即 = 0x40900000
以下tool.c
是一個(gè)測(cè)試工具:
// tool.c
#include <stdio.h>
#include <stdlib.h>
// 打印一個(gè)計(jì)算機(jī)存儲(chǔ)的浮點(diǎn)數(shù)值
void print_bin_to_float(unsigned long hex){
float* fp=(float*)&hex;
printf("%lx,%f\n",hex,*fp);
}
// 打印一個(gè)浮點(diǎn)數(shù)在計(jì)算機(jī)存儲(chǔ)的十六進(jìn)制表示
void print_float_to_bin(float f){
unsigned long* pf = (unsigned long*)&f;;
printf("%f,0x%lx\n",f,*pf);
}
// 反轉(zhuǎn)字符串
char * reverse_str(char *str, long len){
char *start = str;
char *end = str + len - 1;
char ch;
if (str != NULL)
{
while (start < end)
{
ch = *start;
*start++ = *end;
*end-- = ch;
}
}
return str;
}
// 十六進(jìn)制轉(zhuǎn)二進(jìn)制字符串
char * hex_to_bin(unsigned long long hex,int bin_max_len){
printf("0x%llx,hex_to_bin:\n",hex);
char bin_ar[1024] = {0};
long count = 0;
unsigned long long quotient = 0;
int remainder = 0;
do{
quotient = hex / 2;
remainder = hex % 2;
//轉(zhuǎn)換成顯示的數(shù)字字符
char save = '0' + remainder;
bin_ar[count] = save;
hex = quotient;
count ++;
} while (quotient != 0);
while (count < bin_max_len){
bin_ar[count] = '0';
count ++;
}
char *result = reverse_str(bin_ar,count);
printf("0b%s\n",result);
printf("\n");
return result;
}
int main(){
print_float_to_bin(4.5); // 0x40900000
print_float_to_bin(0.5); // 0x3f000000
print_float_to_bin(0.05); // 0x3d4ccccd
print_float_to_bin(0.15625); // 0x3e200000
/*
4.5
0x40900000,hex_to_bin:
0b01000000100100000000000000000000
*/
hex_to_bin(0x40900000,32);
return 0;
}
下面是我們把上述二進(jìn)制轉(zhuǎn)為二進(jìn)制浮點(diǎn)數(shù)
4.5
0x40900000 十六進(jìn)制表示
sign exponent fraction
0 10000001 00100000000000000000000
0 129 00100000000000000000000
階碼 129-127 = 2
0 2 00100000000000000000000
先向右移動(dòng)小數(shù)點(diǎn)2位
0 2 00.100000000000000000000
在向首位補(bǔ)1
0 2 1 00.100000000000000000000
結(jié)果 100.100000000000000000000
如果得到階碼是負(fù)數(shù)比如下面的0.5
和0.05
崖堤,規(guī)則是先在首位補(bǔ)1
侍咱,然后向左移動(dòng)小數(shù)點(diǎn),不夠補(bǔ)0
0.5
0x3f000000 十六進(jìn)制表示
sign exponent fraction
0 01111110 00000000000000000000000
0 01111110 00000000000000000000000
0 126 00000000000000000000000
階碼 126-127 = -1
0 -1 00000000000000000000000
先在左側(cè)補(bǔ)1
0 -1 1 00000000000000000000000
再向左移動(dòng)小點(diǎn)1位
0 -1 0.1 00000000000000000000000
結(jié)果就是 0.1 00000000000000000000000
0.05
0x3d4ccccd 十六進(jìn)制表示
sign exponent fraction
0 01111010 10011001100110011001101
0 122 10011001100110011001101
階碼 122-127 = -5
0 -5 10011001100110011001101
先在左側(cè)補(bǔ)1
0 -5 1 10011001100110011001101
再向左移動(dòng)小點(diǎn)5位密幔,不夠插入0
0 -1 0.00001 10011001100110011001101
結(jié)果就是 0.0000110011001100110011001101
綜上我們知道
階碼為正小數(shù)點(diǎn)右移
楔脯,先移動(dòng)小數(shù)點(diǎn)再補(bǔ)1
。
階碼為負(fù)小數(shù)點(diǎn)左移
胯甩,先補(bǔ)1
再移動(dòng)小數(shù)點(diǎn)昧廷,不足補(bǔ)0
二進(jìn)制浮點(diǎn)數(shù)轉(zhuǎn)10進(jìn)制浮點(diǎn)數(shù),這里是單精度偎箫,雙精度同理
0.15625
0x3e200000
sign exponent fraction
0 01111100 01000000000000000000000
0 01111100 01000000000000000000000
0 124 01000000000000000000000
0 -3 01000000000000000000000
先在左側(cè)補(bǔ)1
0 -3 1 01000000000000000000000
再向左移動(dòng)小點(diǎn)3位木柬,不夠插入0
0 -3 0.001 01000000000000000000000
結(jié)果就是 0.00101000000000000000000000 = 0.00101
根據(jù)公式定義:
0.15625
二進(jìn)制表示如下:
轉(zhuǎn)換如下:
參考
IEEE754 Wiki
單精度浮點(diǎn)數(shù)
雙精度浮點(diǎn)數(shù)
浮點(diǎn)數(shù)表示
二進(jìn)制浮點(diǎn)數(shù)在線轉(zhuǎn)換