C++浮点数的存储方式

类型float大小为4字节,即32位,内存中的存储方式如下:

  1. 最高位 31 位 ,保存符号位 S,“0”表示正数 ,“1”表示负数
  2. 第30 位~23 位 ,共 8 位 ,保存指数部分(指数值加上偏移量127) ,称为阶码
  3. 第22 位~0 位 ,共 23 位 ,保存系数部分 (整数位的1不保存),称为尾数

类型double大小为8字节,即64位,内存布局如下:

  1. 最高位 63 位 ,保存符号位 S,“0”表示正数 ,“1”表示负数
  2. 第 62 位~52 位 ,共 11 位 ,保存指数部分(指数值加上偏移量1023) ,称为阶码
  3. 第 51 位~0 位 ,共 52 位 ,保存系数部分 (整数位的1不保存),称为尾数

如,十进制浮点数2.5的二进制形式为10.1,转换为科学计数法形式为(1.01)(21)(1.01)∗(21),由此可知指数为1,尾数(即科学计数法的小数部分)为01。

根据浮点数的存储标准(IEEE制定),float类型指数的起始数为127(二进制0111 1111),double类型指数的起始数为1023(二进制011 1111 1111),在此基础上加指数,得到的就是内存中指数的表示形式。尾数则直接填入,如果空间多余则以0补齐,如果空间不够则0舍1入。所以float和double类型分别表示的2.5如下(二进制):

符号位 : 0
指数 : 1000 0000
尾数 : 010 0000 0000 0000 0000 0000

符号位 : 0
指数 : 100 0000 0000
尾数 : 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

特别说明:

以单精度浮点数为例,单精度浮点数的指数部分所能表达的实际指数的范围是-126~+127,指数部分是-126~+127加上127 ,指数值的大小从1~254(0和255是特殊值)。浮点小数计算时,指数值减去偏正值将是实际的指数大小。

如果浮点数的指数部分的编码值是0,尾数为非零,那么这个浮点数将被称为非规约形式的浮点数。IEEE 754标准规定:非规约形式的浮点数的指数偏移值比规约形式的浮点数的指数偏移值大1。例如,最小的规约形式的单精度浮点数的指数部分编码值为1,指数的实际值为-126;而非规约的单精度浮点数的指数域编码值为0,对应的指数实际值也是-126而不是-127。实际上非规约形式的浮点数仍然是有效可以使用的,只是它们的绝对值已经小于所有的规约浮点数的绝对值;即所有的非规约浮点数比规约浮点数更接近0。

除此之外还有3个特殊值:

  1. 如果 指数 是0 并且 小数部分 是0, 这个数是±0 (和符号位相关)
  2. 如果 指数 = 2e12e−1 (e为阶码的位数)并且 小数部分 是0, 这个数是 ±无穷大 (同样和符号位相关)
  3. 如果 指数 = 2e12e−1并且 小数部分 非0, 这个数表示为不是一个数(NaN)
形式指数小数部分
00
非正规形式0非0
正规形式1~2e22e−2任意
无穷2e12e−10
NaN2e12e−1非0
C++中,浮点数的表示、精度以及运算方式都受到IEEE 754标准的影响。该标准定义了浮点数的存储格式和基本操作规则,以确保跨平台的一致性[^4]。 ### 浮点数的表示 C++支持多种浮点类型,包括`float`(通常是32位)、`double`(通常是64位)和`long double`(通常为80位或更多)。这些类型的底层表示遵循IEEE 754标准,其中每个浮点数由三个部分组成:符号位、指数位和尾数位。这种结构允许表示非常大或非常小的数值,但也引入了精度问题[^1]。 例如,一个`float`类型的变量可能只能精确地表示某些十进制小数,而其他值则会因为无法准确转换成二进制形式而导致轻微误差。这是由于许多十进制分数在二进制下是无限循环的,就像1/3在十进制下是0.333...一样。 ### 精度与舍入 当处理浮点数时,精度丢失是一个常见的问题。为了管理这种精度,可以采用截断(truncation)或者四舍五入(rounding)等技术来控制固定点数的精度[^3]。默认情况下,IEEE 754使用的是向最接近值舍入的方式,这通常意味着如果最后一位要被丢弃的部分大于等于一半,则向上整;否则向下整[^4]。 对于需要更高精度的应用程序,可以通过调整编译器设置或使用特定的数据结构来提高精度。比如,在PHP中,通过修改`precision` ini设置可以显示更多的数字[^5]。虽然这不是直接适用于C++的情况,但类似的策略也可以应用,如使用更高精度的类型或自定义数据结构。 ### 运算一致性 尽管IEEE 754提供了基础保证,但在不同的硬件平台上执行相同的浮点运算可能会得到略微不同的结果。这是因为不同厂商的CPU实现细节可能存在差异。Intel C++ Compiler文档提到,保持浮点计算的一致性对于避免因平台差异导致的问题至关重要[^2]。 下面是一个简单的C++代码示例,演示如何打印出两个浮点数相加的结果: ```cpp #include <iostream> #include <iomanip> // std::setprecision int main() { float a = 0.1f; float b = 0.2f; float result = a + b; // 使用更高的精度输出查看实际存储的值 std::cout << "Result with default precision: " << result << std::endl; std::cout << "Result with higher precision: " << std::setprecision(9) << result << std::endl; return 0; } ``` 这段代码展示了即使是很简单的加法也可能产生不精确的结果,并且通过设置输出流的精度可以帮助我们看到真实的数值。 ### 结论 理解并正确处理浮点数的精度问题是编写可靠软件的关键之一。开发者应该意识到潜在的精度损失,并采适当措施,比如选择合适的类型、利用语言特性或库函数来帮助管理和提升数值计算的准确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值