C++ float的内存布局

IEEE754标准中,浮点数的内存布局

以下仅以float(内存中占据4个字节,32bits)来说明,double(8个字节,64bits)同理,只是有细微的差别。

float的内存分布

IEEE754规定,32bit的float在内存中是这样分布的:

符号位(S) 阶码(E) 尾数(M)
1 8 23

整数、浮点数在内存中都是以二进制的形式存在的(补码),而浮点数是二进制下的科学计数法存储在内存中的。可以表示 为:$ s 1.m^e$

  • 符号位占据一个比特,当S = 0时表示正数,当S = 1时表示负数。
  • 阶码e则是其指数再加上一个偏移量(127)后的数,其总共占据了8个字节,8位无符号数的范围是0~255,考虑到已经加了一个偏移量,则其实际可表达的范围是-128~127(这个范围是指二进制计数法下的范围)。
  • 尾数m占据了23个字节,由于是使用的二进制下的科学计数法,所以任何浮点数(除了0)都隐含了一个1,也就是说,其尾数实际上在前面应该再加一个1,即:1.m,这样,浮点数的二进制精度是24位,而$2^{24} = 16777216$,所以其十进制下的精度是7位有效数字。
计算实例

1, 十进制与二进制的互转

二进制转十进制比较简单,就是对应位乘以对应的2的幂次,比如:101.1011,其转换过程为:

$$1*2^2 + 0 * 2^1 + 1 * 2^0 + 1 * 2^{-1} + 0 * 2^{-2} + 1 * 2^{-3} + 1 * 2^{-4}$$

十进制整数转二进制比较简单,一是8421来凑,一是除2倒序排,不再解释。

十进制小数转二进制,就是一直乘2,如果大于1,则置1,如果小于1,则置0,一直乘2,直到为0或达到指定位数为止。

比如0.125:

$$ 0.25 * 2 = 0.5 --- 0 \ 0.5 * 2 = 1 --- 1$$

则其二进制为:0.01。

再比如:0.632:

$$ 0.632 * 2 = 1.264 --- 1 \ 0.264 * 2 = 0.528 ---0 \ 0.528 * 2 = 1.056 ---1 \ 0.056 * 2 = 0.112 ---0 \ ...$$

则其二进制为:0.1010….。

2, 计算float的内存布局

2.1 考虑float fa = 4.25,那么:int ia = *(int*)&fa是多少呢?

我们知道,4.25 = 100.01,化成指数表示为:$1.0001*2^2$,则其符号位S = 0, 阶码e = 2 + 127 = 0x81,其尾数部分二进制表示为:1000 1000 0000 0000 0000 0000,总共24位,将尾数的最高位的1去掉,再与阶码e,符号位S组合后:

符号位(S) 阶码(E) 尾数(M)
0 1000 0001 000 1000 0000 0000 0000 0000

合起来就是:

0100 0000 1000 1000 0000 0000 0000 0000,即:ia = 0x40880000

2.2 再考虑float fa = -0.0125,那到:c++ int ia = *(int*)&fa是多少呢?

-0.0125 = -0.00000011001100110011001100...,转换成指数为:$-1.10011001100110011001100…*2^{-7}$,则其符号位S = 1,阶码e = -7 + 127 = 0x78,其尾数部分用二进制表示为:1100 1100 1100 1100 1100 1101,后面的位数就被四舍五入截断了,由于最后一位的后一位是1,则向前进1,同样保留24位,将其最高位的1去掉,再与阶码和符号位组合:

符号位(S) 阶码(E) 尾数(M)
1 0111 1000 100 1100 1100 1100 1100 1101

全起来就是:

1011 1100 0100 1100 1100 1100 1100 1101,即:ia = 0xbc4ccccd

如果将ia转换成fa,则转换过程相反。

来自为知笔记(Wiz)

时间: 2024-10-10 01:26:59

C++ float的内存布局的相关文章

【转载】图说C++对象模型:对象内存布局详解

原文: 图说C++对象模型:对象内存布局详解 正文 回到顶部 0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看.本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有所不同.文章如果有解释不清.解释不通或疏漏的地方,恳请指出. 回到顶部 1.何为C++对象模型? 引用<深度探索C++对象模型>这本书中的话: 有两个概念可以解释C++对象模型: 语言中直接支持面向对象程序设计的部分. 对于各种支持的底层

C++派生类的成员内存布局

class A {}; class B : public virtual A {}; class C : public virtual A {}; class D : public B, public C {}; int main() { A a; B b; C c; D d; cout << sizeof(a) << endl; cout << sizeof(b) << endl; cout << sizeof(c) << endl

c++ 对象内存布局详解

今天看了的,感觉需要了解对象内存的问题. 1.何为C++对象模型? 引用<深度探索C++对象模型>这本书中的话: 有两个概念可以解释C++对象模型: 语言中直接支持面向对象程序设计的部分. 对于各种支持的底层实现机制. 直接支持面向对象程序设计,包括了构造函数.析构函数.多态.虚函数等等,这些内容在很多书籍上都有讨论,也是C++最被人熟知的地方(特性).而对象模型的底层实现机制却是很少有书籍讨论的.对象模型的底层实现机制并未标准化,不同的编译器有一定的自由来设计对象模型的实现细节.在我看来,对

对象的内存布局

对象内存布局 在Hotspot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头,实例数据,对齐填充. 1.对象头 1.1 存储对象自身的运行时数据(mark word):哈希码,gc分代年龄. 1.2 Class指针:通过该指针确定该对象是哪个类的实例. 在64位系统中,class指针占4B,mark word在开启指针压缩的时候占4B;未开启指针压缩的时候占8B. 在32位系统下,上面两部分各占4B; 2.实例数据 默认分配策略:long/double ->  int/float ->

面试 -- Java内存布局【图】以及java各种存储区【详解】

一.Java内存布局浅谈 1. 总述 我们知道,线程是操作系统调度的基本单元.所有线程共享父进程的堆空间,而每个线程都有自己的栈空间和程序计数器.所以,Java虚拟机也看以看作是一个独立的进程,里面的内存空间分为线程共享空间和线程独有空间.Java虚拟机内存布局如下: 2. 所有线程共享的内存空间 (1)堆空间:JVM规范中规定,所有对象实例以及数组都要在堆上进行分配.一般来说,堆空间都有一个默认大小,取决于JVM实现,而且可以根据需要动态扩展.当创建对象需要在堆上分配空间,而且堆本身的空间不够

使用sos查看.NET对象内存布局

前面我们图解了.NET里各种对象的内存布局,我们再来从调试器和clr源码的角度来看一下对象的内存布局.我写了一个测试程序来加深对.net对象内存布局的了解: using System; using System.Runtime.InteropServices; // 实际上是一个C语言里的联合体 [StructLayout(LayoutKind.Explicit)] public struct InnerStruct { [FieldOffset(0)] public float FloatVa

MSVC查看类的对象内存布局

虽说自己对内存对象内存布局这一块还算比较熟悉(鄙人这么认为),但是实际要可视化一个内存布局,还是没做过,今天在网上瞎逛,突然发现了MSVC居然支持输出对象的布局结构,这个命令嘛,就是-d1reportSingleClassLayout和-d1reportAllClassLayout了. 顾名思义,前者用于输出指定名字的类的结构,后者则是输出全部的类的结构,试了下后面的命令,发现按下Enter键后,留给鄙人的不是这个文件所得对应的类的内存结构,而是将近几秒的刷屏.....所以还是-d1report

Hotspot对象的内存布局

对象头 class oopDesc { ... private: volatile markOop _mark; union _metadata { Klass* _klass; narrowKlass _compressed_klass; } _metadata; ... } 在hotspot中对象指针称为oop(ordinary object pointer),而oopDesc则是对象头的结构..除了Klass(之所以叫klass是因为class是C++关键字)指针外,,还由一个_mark字

C语言程序的内存布局

一:C语言程序的存储区域 C语言编写的程序经过编绎-链接后,将形成一个统一的文件,它由几个部分组成,在程序运行时又会产生几个其他部分,各个部分代表了不同的存储区域: 1.代码段(Code or Text): 代码段由程序中的机器码组成.在C语言中,程序语句进行编译后,形成机器代码.在执行程序的过程中,CPU的程序计数器指向代码段的每一条代码,并由处理器依次运行. 2.只读数据段(RO data): 只读数据段是程序使用的一些不会被更改的数据,使用这些数方式类似查表式的操作,由于这些变量不需要更改