整形数int、浮点型数据float,在内存中存储的表示

本文详细解析了整型(int)和浮点型(float)数据在内存中的存储方式,介绍了无符号整型(unsigned int)和有符号整型(signed int)的存储原理,并深入探讨了浮点型数据如何通过符号位、指数部分和小数部分来表示一个实数。
引言: 突然想到一个底层问题。
计算机组成原理里学的:定点整数 定点小数 浮点数;
编程里的基本数据类型int float在内存中的存储形式;
二者究竟的对应关系是?
CSDN博客里有这样一句话,“实数在内存中以规范化的浮点数存放”,请先理清“实数”是多大范围再回味这句话!
我在书上看到这样一句话,“一般高档微机以上的计算机中同时采用定点、浮点表示,由使用者进行选择,而单片机多采用定点表示”,可以猜测这个“使用者”应该指的是各中编程语言的编译器咯!


正文整形数int、浮点型数据float,在内存中存储形式表示方法
*****float型在内存中占4个字节,即32位,同样int或long型也占4个字节,在对各自的32位进行逐位分解后发现,它们所代表的具体意义却相差甚远。


*****首先分解整形的32位,对于无符号整形(unsigned int) ,分解如下:至右向左把第i位的值记为bi(0或1),则这一位代表的十进制数值为:bi * 2^i, i=0,2,...31。整形的4个字节(32位)二进制数折算成十进制数为:b31 * 2^31 + ... + bi * 2^i + ... + b1 * 2 + b0 * 1 ——记为“公式@”。


*****对于有符号整形(signed int),最高位(第31位)代表符号,0正1负,剩余的31位必须减1再各位取反,记为“操作#”,然后按以上“公式@”得出这个整形数的绝对值。


*****以上作为一个引子,以下float分解也必须建立在此基础上,记住“操作#”和“公式@”两个约定的含义。同时纠正一下提问者的说法“能表达的范围应该也就0-2^32”,整型准确的数值范围为:有符号( (-2^31) —— (2^31-1)),无符号( 0 —— (2^32-1) )。下面引导到关键问题上,float的32位在内存中到底分别代表什么意义?
    
*****把所有32位用b31-b0(从高到低)表示,b31同样是符号位,其意义为0正1负。b30-b23总共8位是一个有符号整形(signed int),先后用“操作#”和“公式@”计算得到一个数值E (十进制范围是-128 —— 127),再由它经过指数运算得到2^E,十进制范围是:1.0 * 10^(-38) —— 1.7 * 10^38 。余下的23位b22-b0代表小数值,其中b22代表的十进制数值为:b22 * 2^(-1)即b22 * 0.5, b21代表的十进制数值为:b22 * 2^(-2)即b22 * 0.25,以此类推,所以小数范围为0 —— 1(实际为0.0000…1 至 0.9999…) 。


*****从以上分解可知,float的32位都有了各自的意义,可以分为3块,符号块S (b31),指数块E (b30-b23),小数块D(b22-b0),但如何组装成一个实际的小树呢?具体算法就是:
(-1)^S * (1.0 + D) * 2^E ,最终数值范围是-3.4*10^-38 —— 3.4*10^38。


*****最后提醒一下,所有浮点数在进出内存时都经过相应的硬件进行以上“操作#”和“公式@”。编程人员无需深究其中细节,如若是出于好奇心,那是值得理解并支持地。
<think>我们正在讨论浮点转换为整时内中的数据变化。根据IEEE 754标准,浮点在内中的表示与整完全不同。浮点通常由符号位、指部分和尾部分组成,而整则是直接以二进制补码形式表示(对于有符号整)。 当我们将一个浮点转换为整时,计算机会执行以下步骤: 1. 检查浮点是否在目标整类型的表示范围内。如果超出范围,行为可能是未定义的(如C/C++)或抛出异常(如Java)或返回边界值(如Python)。 2. 如果浮点在范围内,则截断小部分(向零取整)得到整值。 3. 将该整值按照目标整类型的二进制表示形式存储。 内变化: 浮点的内布局(以32位单精度为例): - 1位符号位(S) - 8位指位(E) - 23位尾位(M) 整的内布局(以32位有符号整为例): - 直接使用32位二进制补码表示。 因此,转换过程中,内中的数据会发生根本性的改变。例如,浮点3.14在内中的表示与整3的表示完全不同。 举例说明: 浮点3.14(单精度)的二进制表示(IEEE 754): 符号位:0(正) 指部分:10000000(偏移127,实际指为128-127=1) 尾部分:10010001111010111000011(近似表示0.14的二进制小部分) 整个32位:0 10000000 10010001111010111000011 而整3的32位二进制补码表示: 00000000 00000000 00000000 00000011 因此,转换后,内中原来存储浮点的位模式被完全替换为整的位模式。 我们还可以参考引用[4]中提到的例子:将11.375转换成IEEE 754浮点格式,然后再将其转换为整。整11的二进制表示与浮点的二进制表示完全不同。 步骤总结: 1. 浮点在内中按照IEEE 754标准存储(以单精度或双精度)。 2. 转换时,计算机会根据浮点的值计算出对应的整(去掉小部分,注意溢出)。 3. 将计算得到的整按照目标整类型(如int32, int64等)的二进制补码形式入内。 注意:在转换过程中,小部分会被丢弃(截断),而不是四舍五入。例如,3.9转换为整会得到3,-3.9转换为整会得到-3。 另外,引用[3]提到浮点的小在转换时可能在舍入误差,但这里我们讨论的是截断,所以误差仅来自于小部分的直接丢弃。 下面我们用一个具体的C++代码示例来展示转换过程(注意:这里我们无法直接看到内变化,但我们可以通过打印内字节来观察): 假设我们有一个浮点f = 3.14f,将其转换为整i = (int)f。 我们可以通过以下方式查看内表示(示例代码,仅用于说明): ```cpp #include <iostream> #include <iomanip> #include <cstring> int main() { float f = 3.14f; int i = static_cast<int>(f); // 显式转换 // 打印浮点的内表示 unsigned char* p_float = reinterpret_cast<unsigned char*>(&f); std::cout << "浮点表示(16进制): "; for (int j = 0; j < sizeof(float); j++) { std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(p_float[j]) << " "; } std::cout << std::endl; // 打印整的内表示 unsigned char* p_int = reinterpret_cast<unsigned char*>(&i); std::cout << "整表示(16进制): "; for (int j = 0; j < sizeof(int); j++) { std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(p_int[j]) << " "; } std::cout << std::endl; return 0; } ``` 运行结果(在小端序机器上): 浮点3.14的表示(单精度):0x4048f5c3(在内中字节顺序为:c3 f5 48 40,因为小端序) 整3的表示:0x00000003(在内中字节顺序为:03 00 00 00) 可以看到,内中的字节完全不同。 总结:浮点转整时,内中的数据会从浮点的IEEE 754表示转换为整的二进制补码表示,且小部分被截断。 §§相关问题§§ 1. 浮点转换为整时,如何处理溢出情况? 2. 为什么浮点的小部分在转换时会被截断而不是四舍五入? 3. 能否通过直接复制内的方式将浮点转换为整?为什么? 4. 不同编程语言在浮点转整时有哪些差异?</think>### 浮点转整的内数据变化分析 当浮点转换为整时,内中的数据会发生以下本质变化(以32位单精度浮点转32位整为例): #### 1. **内布局重构** 浮点(IEEE 754标准)和整的内结构完全不同: - **浮点内结构**(4字节): $$ \underbrace{1\ \text{位}}_{\text{符号}} \mid \underbrace{8\ \text{位}}_{\text{指}} \mid \underbrace{23\ \text{位}}_{\text{尾}} $$ 例如 `3.14` 的十六进制:`0x4048F5C3` - **整结构**(4字节补码): 直接存储二进制值,例如 `3` 的十六进制:`0x00000003` #### 2. **转换核心步骤** 1. **分离符号与值** 提取浮点的符号位(确定正负)和尾部分(有效字)。 2. **指调整** 根据指位计算实际位移量。例如浮点 $11.375$: - 整部分 $11$ 的二进制:$1011_2$(通过引用[4]的除法转换) - 指值 $E = \text{指域} - 127$ 3. **截断小** 直接丢弃小部分(非四舍五入),例如: ```python # Python示例(引用[1]) int(3.14) # 结果=3,小部分0.14被丢弃 ``` 4. **补码转换** 将截断后的整值转为二进制补码: - 正:原码 = 补码 - 负:取反加一 #### 3. **内变化实例** 以浮点 $11.375$ → 整 $11$ 为例: | 步骤 | 浮点表示(IEEE 754) | 整表示(补码) | |------------------|-----------------------------|-----------------------| | 原始内 | `0x41360000` (十六进制) | 无效 | | 转换后内 | 无效 | `0x0000000B` (十六进制)| | 二进制展开 | `0100 0001 0011 0110 0000...` | `0000 0000 0000 1011` | > 💡 关键区别:浮点的指/尾结构被完全替换为整的线性二进制值。 #### 4. **特殊场景处理** - **溢出处理**(如 $10^{20}$ 转 int) 超出整范围时: - C++:未定义行为(引用[2]) - Java/Python:保留低位或报错(引用[3]) - **精度损失** 浮点小无法精确存储(引用[3]): $$ 0.1 + 0.2 \neq 0.3 \quad \text{(二进制舍入误差)} $$ #### 5. **验证代码(C++)** ```cpp #include <iostream> #include <bitset> int main() { float f = 11.375f; int i = static_cast<int>(f); // 显式转换(引用[2]) // 打印内数据 std::cout << "浮点: " << std::bitset<32>(*(int*)&f) << "\n"; // 二进制展开 std::cout << "整: " << std::bitset<32>(i) << "\n"; return 0; } ``` **输出**: ``` 浮点: 01000001001101100000000000000000 整: 00000000000000000000000000001011 ``` ### 总结 浮点转整的本质是**内数据的完全重构**: 1. IEEE 754的三段式结构被破坏 2. 新内写入整补码 3. 小部分被不可逆丢弃 4. 符号和整值得以保留 此过程解释了为什么直接内复制(如`memcpy`)无法实现正确转换[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值