计算机中浮点数的表示

浮点数转二进制浮点数

整数部分:

  1. 整数部分不断除以2,保存商和余数。
  2. 判断商是否等于0,如果等于0到第3步,否则回到第1步。
  3. 将每一步得到的余数倒序保存,得到整数部分的二进制表示。

小数部分:

  1. 小数部分不断乘以2,保存结果的整数和小数。
  2. 判断结果的整数是否等于1,如果等于1到第3步,否则回到第1步。
  3. 将每一步结果的所有整数顺序保存,就得到小数的二进制表示

例如:浮点数 4.8125
整数部分:

4/2     = 2     0
2/2     = 1     0
1/2     = 0     1
所以整数部分 4 的二进制为 100

小数部分:

0.8125*2    = 1.625     1
0.625*2     = 1.25      1
0.25*2      = 0.5       0
0.5*2       = 1.0       1
所以小数部分 0.8125 的二进制位 1101

将整数与小数部分连接起来就是 100.1101,即4.8125=100.1101_2

再如:浮点数 0.05
因为只有小数所以只处理小数部分:

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 
......      无限循环


所以0.05的二进制 = 0.0000 1100 1100 1100 1100 1100 1101 .... 

可以看到二进制小数是无法准确表示浮点数的,所以就有了精度一说.
单精度浮点数用32位二进制表示如下:

符号位1位  阶码8位  小数位23位
单精度.jpg

双精度浮点数用64位二进制表示如下:

符号位1位  阶码11位  小数位52位
双精度.png

由上可知,
单精度浮点数精度为 pow(2,23) = 8388608 = 0.8388608 x pow(10,7)
所以单精度浮点数对应的10进制精度为 7 位多
双精度浮点数精度为 pow(2,52)-1 = 4503599627370496 = 0.4503599627370496 x pow(10,16)
所以双精度浮点数对应的10进制精度为 16 位多

浮点数的计算机表示 (IEEE754标准)

移码(又叫增码)是由补码的符号位取反得到,一般用指数的移码减去1来做浮点数的阶码,
引入的目的是便于浮点数运算时的对阶操作。为了保证浮点数的机器零为全0。

对于定点整数,计算机一般采用补码的来存储。
正整数的符号位为 0,反码、补码、原码都一样。
负整数的符号位为 1,原码、反码和补码的表示各不相同,

由原码变成反码和补码有如下规则:

  1. 原码符号位为1不变,整数的每一位二进制数位取反得到反码;
  2. 反码符号位为1不变,反码数值位最低位加1得补码。
比如,以一个字节 8bits 来表示 -3,
那么-3的各种码,原码-->反码-->补码--->移码
原码:[ − 3 ] = 1 000001 1,最高位1位符号位
反码:[ − 3 ] = 1 111110 0,原码符号位不变,其他位取反
补码:[ − 3 ] = 1 111110 1,反码符号为不变,最低位加1
移码:[ − 3 ] = 0 111110 1,补码符号为取反

浮点数二进制表示:
V=(-1)^s*(1.M)*2^E

s:符号位,0正数,1负数
M:小数部分,使用原码表示
E:阶码,使用其原码+127表示或者用其移码-1表示,

比如十进制4.5的单精度浮点数的二进制 = 100.1_2 表示为上述公式则为
4.5=(-1)^0*(1.001)*2^2
看到这里的E2,那么它在计算机实际存储为 2 + 127 = 129 = 10000001_2

根据上面的公式各部分表示的规则得到一个32位浮点数表示如下表:

符号位s:1位 阶码E:2~9位 小数位M:10~32位
0 2+127=129 001
0 10000001 00100000000000000000000

符号位为0表示是正数,所以4.5的二进制存储为0 10000001 00100000000000000000000,即1000000100100000000000000000000_2 = 0x40900000

以下tool.c是一个测试工具:

// tool.c
#include <stdio.h>
#include <stdlib.h>
// 打印一个计算机存储的浮点数值
void print_bin_to_float(unsigned long hex){
    float* fp=(float*)&hex;
    printf("%lx,%f\n",hex,*fp);
}
// 打印一个浮点数在计算机存储的十六进制表示
void print_float_to_bin(float f){
    unsigned long* pf = (unsigned long*)&f;;
    printf("%f,0x%lx\n",f,*pf);

}
// 反转字符串
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;
}
// 十六进制转二进制字符串
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;
        //转换成显示的数字字符 
        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;
}



下面是我们把上述二进制转为二进制浮点数

4.5
0x40900000 十六进制表示
sign    exponent    fraction
0       10000001    00100000000000000000000
0       129         00100000000000000000000
阶码 129-127 = 2
0       2           00100000000000000000000
先向右移动小数点2位
0       2           00.100000000000000000000
在向首位补1
0       2         1 00.100000000000000000000
结果 100.100000000000000000000

如果得到阶码是负数比如下面的0.50.05,规则是先在首位补1,然后向左移动小数点,不够补0

0.5
0x3f000000 十六进制表示
sign    exponent    fraction
0       01111110    00000000000000000000000
0       01111110    00000000000000000000000
0       126         00000000000000000000000
阶码 126-127 = -1
0       -1          00000000000000000000000
先在左侧补1
0       -1        1 00000000000000000000000
再向左移动小点1位
0       -1      0.1 00000000000000000000000
结果就是 0.1 00000000000000000000000

0.05
0x3d4ccccd 十六进制表示
sign    exponent    fraction
0       01111010    10011001100110011001101
0       122         10011001100110011001101
阶码 122-127 = -5
0       -5          10011001100110011001101
先在左侧补1
0       -5        1 10011001100110011001101
再向左移动小点5位,不够插入0
0   -1      0.00001 10011001100110011001101

结果就是 0.0000110011001100110011001101

综上我们知道
阶码为正小数点右移,先移动小数点再补1
阶码为负小数点左移,先补1再移动小数点,不足补0

二进制浮点数转10进制浮点数,这里是单精度,双精度同理

0.15625
0x3e200000
sign    exponent    fraction
0       01111100    01000000000000000000000
0       01111100    01000000000000000000000
0       124         01000000000000000000000
0       -3          01000000000000000000000
先在左侧补1
0       -3          1 01000000000000000000000
再向左移动小点3位,不够插入0
0       -3          0.001 01000000000000000000000
结果就是 0.00101000000000000000000000 = 0.00101



根据公式定义:
V=(-1)^s*1.M*2^E

0.15625二进制表示如下:
V=(-1)^0*1.01*2^{-3}

转换如下:
sign=+1
exponent = (-127) + 124 = -3
fraction = 1*2^0 + 0*2^{-1} + 1 * 2^{-2} = 1.25
value= (+1) * 1.25 * 2^{-3} = +0.15625

参考

IEEE754 Wiki
单精度浮点数
双精度浮点数
浮点数表示
二进制浮点数在线转换

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容