zoukankan      html  css  js  c++  java
  • 浮点数类型转换的及其内存模型

    先看一段测试code:

    void  do_test() {
        unsigned int uValue = 0xC1480000;
        printf("uValue = %u,%d,%x,&uValue = %p
    ",uValue,uValue,uValue,&uValue);
    
        float fValue1 = (float) uValue;
        printf("fValue1 = %f,&fValue1 = %p, *((unsinged int*)&fValue1) = %x
    ",fValue1,&fValue1,*((unsigned int*)&fValue1));
    
        float fValue2 = *((float*) &uValue);
        printf("fValue2 = %f,&fValue2 = %p, *((unsinged int*)&fValue2) = %x
    ",fValue2,&fValue2,*((unsigned int*)&fValue2));
    }

    它的运行结果为:

    uValue = 3242721280,-1052246016,c1480000,&uValue = 0xbe99b59c
    fValue1 = 3242721280.000000,&fValue1 = 0xbe99b5a0, *((unsinged int*)&fValue1) = 4f414800
    fValue2 = -12.500000,&fValue2 = 0xbe99b5a4, *((unsinged int*)&fValue2) = c1480000

    首先第一段uValue:

    它的16进制表达方式也就是内存里面的值为0xC1480000;

    将数据0xC1480000表示成unsigned int,它的值是3242721280;

    将数据0xC1480000表示成int,它的值是-1052246016。

    第二段fValue1:

    它的值是从uValue强转而来的;

    它的内存里面的值是0x4F414800,也就是说float fValue1 = (float) uValue;这种强转会改变内存里的值;

    而这个0x4F414800表示成float,它的值是3242721280.000000。

    第三段fValue2:

    它的内存值是uValue的内存值拷贝而来的,是0xC1480000

    而是0xC1480000表示成float,它的值是-12.5,也就是说float fValue2 = *((float*) &uValue);的赋值方式不会改变内存值。

    我们从会变得角度看看上面的几个赋值过程:

    000010e4 <_Z7do_testv>:
        10e4:       b57f            push    {r0, r1, r2, r3, r4, r5, r6, lr}
        10e6:       ab06            add     r3, sp, #24
        ; 第一段
        10e8:       4919            ldr     r1, [pc, #100]  ; (1150 <_Z7do_testv+0x6c>)
        10ea:       481a            ldr     r0, [pc, #104]  ; (1154 <_Z7do_testv+0x70>)
        10ec:       f843 1d0c       str.w   r1, [r3, #-12]!
        10f0:       460a            mov     r2, r1
        10f2:       9300            str     r3, [sp, #0]
        10f4:       4478            add     r0, pc
        10f6:       460b            mov     r3, r1
        10f8:       f7ff ec0e       blx     918 <printf@plt>
        ; 第二段
        10fc:       ed9d 7a03       vldr    s14, [sp, #12]
        1100:       eef8 7a47       vcvt.f32.u32    s15, s14
        1104:       a806            add     r0, sp, #24
        1106:       ee17 2a90       vmov    r2, s15
        110a:       eef7 0ae7       vcvt.f64.f32    d16, s15
        110e:       f840 2d08       str.w   r2, [r0, #-8]!
        1112:       edcd 7a01       vstr    s15, [sp, #4]
        1116:       9000            str     r0, [sp, #0]
        1118:       480f            ldr     r0, [pc, #60]   ; (1158 <_Z7do_testv+0x74>)
        111a:       ec53 2b30       vmov    r2, r3, d16
        111e:       4478            add     r0, pc
        1120:       f7ff ebfa       blx     918 <printf@plt>
        ; 第三段
        1124:       f8dd c00c       ldr.w   ip, [sp, #12]
        1128:       ab06            add     r3, sp, #24
        112a:       480c            ldr     r0, [pc, #48]   ; (115c <_Z7do_testv+0x78>)
        112c:       ee00 ca10       vmov    s0, ip
        1130:       f843 cd04       str.w   ip, [r3, #-4]!
        1134:       4478            add     r0, pc
        1136:       9300            str     r3, [sp, #0]
        1138:       eeb7 1ac0       vcvt.f64.f32    d1, s0
        113c:       f8cd c004       str.w   ip, [sp, #4]
        1140:       ec53 2b11       vmov    r2, r3, d1
        1144:       f7ff ebe8       blx     918 <printf@plt>
        1148:       b007            add     sp, #28
        114a:       f85d fb04       ldr.w   pc, [sp], #4
        114e:       bf00            nop
        1150:       c1480000
        1154:       00000105
        1158:       000000fb
        115c:       00000122

    第二段中的vcvt.f32.u32指令就是u32转成float的,而vcvt.f64.f32是float转double的。

    那第二段为什么会出现vcvt.f32.u32呢?因为print中的%f表示的是double类型,所以fValue1就强制转换成double类型了。

    同样,第三段中,也有vcvt.f64.f32,但第三段不会有vcvt.f32.u32。

    因此浮点数的强制类型转换,会带来内存值的改变,而这个内存值的改变正是用vcvt指令进行的。

    它的转换依据是IEEE标准,可以参考http://blog.csdn.net/demon__hunter/article/details/3566232

    0xC1480000 -> 1100 0001 0100 1000   0000 0000 0000 0000

    符号位:1 表示是负数

    指数位:100 0001 0 = 130

    小数位: 100 1000   0000 0000 0000 0000

    运算方法:

    小数位前面加个1和点‘.’

    1.100 1000   0000 0000 0000 0000

    指数位值减去127,如130-127=3,表示小数点右移3个位,得:

    1100 .1000   0000 0000 0000 0000

    小数点前面的数1100 = 1*(2^3)+1*(2^2)+0*(2^1)+0*(2^0) = 12

    小数点后面的数1000   0000 0000 0000 0000 = 1*(2^-1)+0*(2^-2)+0*(2^-3)+... = 1*(2^-1) = 0.5

    加上符号位后,它的值就是-12.5

    同理:

    0x4F414800 -> 0100 1111 0100 0001 0100 1000 0000 0000

    符号位:0 表示是正数

    数位:100 1111 0 = 158

    小数位: 100 0001 0100 1000 0000 0000

    运算方法:

    小数位前面加个1和点‘.’

    1.100 0001 0100 1000 0000 0000

    指数位值减去127,如158-127=31,表示小数点右移31个位,得:

    1100 0001 0100 1000 0000 0000 0000 0000.

    明显,这个值就没有小数点后面的数了,

    二进制1100 00001 0100  1000 0000 0000 0000 0000转换成十进制就是3242721280

  • 相关阅读:
    .NET Core 使用NPOI读取Excel返回泛型List集合
    C# 判别系统版本以及Win10的识别办法
    WPF 程序员休息数字时钟
    分享一个淘宝/天猫/京东/阿里 图片抓取工具
    记一次数据库同步经历(sql server 2008)
    datagridview 如何显示记载中
    关于如何解决bootstrap table 列 切换 刷新 高度不一样
    js 中 函数的返回值问题
    winform 实现定位
    winform 里 如何实现文件上传
  • 原文地址:https://www.cnblogs.com/YYPapa/p/6854371.html
Copyright © 2011-2022 走看看