美文网首页
计算机中浮点数的表示

计算机中浮点数的表示

作者: 和谐共处 | 来源:发表于2021-09-30 17:12 被阅读0次

    浮点数转二进制浮点数

    整数部分:

    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

    根据上面的公式各部分表示的规则得到如下表:

    符号位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
    单精度浮点数
    双精度浮点数
    浮点数表示
    二进制浮点数在线转换

    相关文章

      网友评论

          本文标题:计算机中浮点数的表示

          本文链接:https://www.haomeiwen.com/subject/znscgltx.html