• 【原创】为什么浮点数1e38f + 1


    1. 问题

        为什么1e38f + 1 - 1e38f为0?

    2. 分析

      

        int ii = 2; //00 00 00 02
    
        int *pii = ⅈ
    
        float i = 1e38f; //7e 96 76 99     (0111 1110  1001 0110  0111 0110  1001 1001)
    
        float j = -1e38f;//fe 9676 99      (1111 1110  1001 0110  0111 0110  1001 1001)
    
        float *pi = &i;
    
        float *pj = &j;
    
        int fs = sizeof(float);
    
        float k = i + j + 1; //3f 80 00 00  (0011 1111 1000 0000 0000 0000 0000 0000)
        float l = i + 1 + j; //00 00 00 00
    
        float *pk = &k;
        float *pl = &l;

    根据IEEE 754single-precision binary floating-point format

    单精度浮点数:4个字节,最高位为符号位,23-30共8位指数,0-22共23为尾数(隐藏了最高位1);指数用移码表示,指数的偏移量为127;尾数用补码表示。

    float i = 1e38f; //99 76 96 7e  (0111 1110  1001 0110  0111 0110  1001 1001)

    符号位:0

    指数:1111 1101

    尾数:001 0110  0111 0110  1001 1001

    float j = -1e38f; //99 76 96 fe (1111 1110  1001 0110  0111 0110  1001 1001)

    符号位:1

    指数:1111 1101(和上面一样有没有)

    尾数:001 0110  0111 0110  1001 1001

    指数对齐,尾数相加,(对齐时,指数向大的对齐,相加前小的指数对应的尾数要右移指数差位)

    这里指数一样大,不用对齐;

    1 = +1 * 2^0

    符号位:0

    指数:127(0111 1111)

    尾数:1(000 0000 0000 0000 0000 0000)

    0 0111 1111 000 0000 0000 0000 0000 0000

    3.  i + 1计算步骤:

    3.1 指数对齐

             1111 1101和0111 1111,差为253-127=126

             尾数相加时要把隐藏的1写出来;

             尾数补上最高位1,再右移126位,由于右移126位超过了23位,尾数都被移除,全被置0。

    3.2 尾数相加

       1001 0110  0111 0110  1001 1001

    +  0000 0000  0000 0000  0000 0000

    = 0 1001 0110  0111 0110  1001 1001

    3.3 溢出判断

         上面的数没有溢出;

         如果溢出将该数右移1位且指数加1

    3.4 结果合成

         由于尾数实际为24位,最高位总为1,实际上只存储23位,最高位不存储。

    去除尾数最高位及指数部分清0:result =result &(~0xFF800000)

    和较大指数合并:result= result| (e1 << 23);

    result即为浮点数的二进制表示了,把它转换成浮点数:c = *((float *)&result);

        由上述可以得出,尾数相加后不变,指数不变,所以和结果不变,仍为较大的那个浮点数。

        进而我们可以得出一个结论:当两个浮点数的指数相差超过浮点数的尾数位数,那么两个浮点数的相加结果将会等于较大的浮点数! 所以1e38f + 1 - 1e38f = 1e38f - 1e38f = 0

     

    4. 代码

    #include <stdio.h>
    
     
    
    // simple ieee 754 single precision float number
    
    // addition arithmetic.
    
    // format:
    
    // S  E   F
    
    // 1  8   23
    
    float test1(float a, float b)
    
    {
    
        float c = 0;
    
        unsigned int p1 = *((unsigned int *)&a);
    
        unsigned int p2 = *((unsigned int *)&b);
    
        unsigned int    t;
    
     
    
        // compute exponent difference
    
        // essentially, we must let two number's exponent be same
    
        int e1 = (p1 << 1) >> 24;
    
        int e2 = (p2 << 1) >> 24;
    
        int diff = e1 - e2;
    
     
    
        if (diff < 0) {
    
            diff = 0 - diff;
    
            t = p1;
    
            p1 = p2;
    
            p2 = t;
    
            e1 = e2;
    
        }
    
        //convert mantissa to signed integer
    
     
    
        // there is a hidden bit
    
        //:) i do not want to handle minus number here
    
        //
    
        int p3 = p1 | 0x00800000;
    
        p3 = p3 & 0x00ffffff;
    
        int p4 = p2 | 0x00800000;
    
        p4 = p4 & 0x00ffffff;
    
        //mantissa should be shift right according to difference of
    
        //exponent.
    
        unsigned int result = p3 + (p4 >> diff);
    
        if (result >= 0x01000000) {
    
            result = result >> 1;
    
            e1 = e1 + 1;
    
        }
    
        // combination
    
        result = result&(~0xFF800000) | (e1 << 23);
    
        c = *((float *)&result);
    
        return c;
    
    }
    
     
    
    int _tmain(int argc, _TCHAR* argv[])
    
    {
    
        float c = test1(4.1f, 1.0f);
    
        return 0;
    
    }
    View Code

    5. 流程图

     

    6. 参考文献

    https://en.wikipedia.org/wiki/Single-precision_floating-point_format

    http://www.cnblogs.com/cornsea/archive/2010/09/18/1830366.html

  • 相关阅读:
    MSSQL '20210806'转换成'2021-08-06'
    cxgrid 列内容居中显示
    CXGRID 导出EXCEL
    study PostgreSQL【3-get数据库中all表以及表的字段信息】
    study PostgreSQL【2-FireDAC连接PostgreSQL】
    高格-销售发票勾稽销售出货的赠品处理【14】
    study PostgreSQL【1-PostgreSQL对象】
    高格-负库存导致系统异常的处理【13】
    study Rust-9【组织管理】
    基础资料属性不符合目标组织要求:物料.允许库存,物料.来料检验
  • 原文地址:https://www.cnblogs.com/cposture/p/4680211.html
Copyright © 2020-2023  润新知