C++填坑:关于float和double

本文详细介绍了十进制和二进制数的表示方法,特别是二进制中的定点和浮点数表示,重点讲解了IEEE浮点标准在32位和64位中的实现。此外,还讨论了整型数据在内存中的存储方式,包括补码表示和大小端模式。文章强调了降低内存使用和一致内存访问对提升效率的重要性。
摘要由CSDN通过智能技术生成


前言

刚开始看计算机图形学,开篇就看见建议使用双精度double进行几何计算,使用单精度float进行色彩计算,对于占用大量内存的数据,例如三角形网格,建议存储float数据,但在通过成员函数访问数据时,将其转换为double。

为啥呢?
现代体系结构表明,降低内存使用和保持一致的内存访问是提高效率的关键。

想起之前看计算机组成原理的时候直接略过了浮点数这一章,赶紧去补了一下基础

一、十进制数如何表示?

十进制数表示法使用的表达形式是这样的: d m d m − 1 . . . d 1 d 0 . d − 1 d − 2 . . . d − n d_md_{m-1}...d_1d_0.d_{-1}d_{-2}...d_{-n} dmdm1...d1d0.d1d2...dn
其中每个十进制数 d i d_i di取值范围在0~9之间,因此 d = ∑ i = − n m 1 0 i ∗ d i d=\sum_{i=-n}^m10^i*d_i d=i=nm10idi
其中i为权,小数点左边从0开始变大,小数点右边从-1开始变小

示例: 12.3 4 10 = 1 ∗ 1 0 1 + 2 ∗ 1 0 0 + 3 ∗ 1 0 − 1 + 4 ∗ 1 0 − 2 12.34_{10}=1*10^1+2*10^0+3*10^{-1}+4*10^{-2} 12.3410=1101+2100+3101+4102

二、二进制数如何表示?

1.定点表示法

和十进制数差不多,二进制数也能表示为相似的权值模式: b = ∑ i = − n m 2 i ∗ b i b=\sum_{i=-n}^m2^i*b_i b=i=nm2ibi

示例: 101.1 1 2 = 1 ∗ 2 2 + 0 ∗ 2 1 + 1 ∗ 2 0 + 1 ∗ 2 − 1 + 1 ∗ 2 − 2 101.11_{2}=1*2^2+0*2^1+1*2^0+1*2^{-1}+1*2^{-2} 101.112=122+021+120+121+122

所以二进制数小数点左移一位,相当于乘以2,右移一位相当于除以2
小技巧:形如 0.11... 1 2 0.11...1_2 0.11...12的二进数表示的是刚好比1小的数,例如 0.11111 1 2 0.111111_2 0.1111112表示的是 63 / 64 63/64 63/64

2.浮点数表示法

IEEE浮点标准: V = ( − 1 ) s ∗ M ∗ 2 E V=(-1)^s*M*2^E V=(1)sM2E
通过上面的式子表示一个数
其中:

  • 符号(sign):s决定这个数的正负,1为负数,0为正数
  • 尾数(significand):M为二进制小数,可以看做长这样 1.1101..11 1.1101..11 1.1101..11之类的,M = 1 + frac
  • 阶码(exponent):E的作用是对浮点数加权,权重是2的E次幂
    在这里插入图片描述
    对于32位的浮点数,最高1位是符号位S,接着是8位的指数E,剩下的23位是有效数字M。
    对于64位的浮点数,最高1位是符号位S,接着的11位是指数E,剩下的52位是有效数字M。

计算机存储是按位进行存储,因此需要弄清楚每一位代表是什么意思,下面是二进制位的阐述

  • 符号位s
  • k位的阶码字段 e x p = e k − 1 . . . e 1 e 0 exp=e_{k-1}...e_1e_0 exp=ek1...e1e0,注意要先让阶码+127,然后转换为2进制的k位阶码,用于偏置
  • n位的小数字段 f r a c = f n − 1 . . . f 1 f 0 frac=f_{n-1}...f_{1}f_0 frac=fn1...f1f0,小数字段 0 < = f < 1 0<=f<1 0<=f<1,隐含了以1开头的表示,因为之前把M看做了 1. f n − 1 . . . f 1 f 0 1.f_{n-1}...f_1f_0 1.fn1...f1f0这样的数字,所以第一位总是1,可以获得一个额外的精度


这里有规格化、非规格化、无穷大和NaN四种情况

  1. 规格化:
    正常表示
  2. 非规格化:
    表示数值0,因为规格化表示中总是让M>=1
  3. 无穷大:
    s=0,正无穷;s=1,负无穷
  4. NaN:
    特殊值,表示不是一个数(Not a Number)

示例:
在这里插入图片描述
在这里插入图片描述

2.1 注意事项

  • 对于有效数字M,因为其值大于等于1而小于2,所以在计算机中,为了能够利用23位(52位)表示更多的数据,IEEE754规定保存M时默认这个数的第一位为1,所以只保存后面的部分(小数点后的位)。然后等到读取此数的时候,再把第一位的1加上去。
  • 对于指数E,为了能够表示负数的指数,IEEE754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数为127;对于11位的E,这个中间数是1023。
  • 当E全为0时,读取该数字时有效数字M不再加上第一位的1,因为这是一个无限接近与0的数字,表示正负0;当E全为1的时候,若M全为0,则表示一个正负无穷大的数。

三、整型与浮点型数据在计算机内存中的存储

看到别的博文有总结,也写进来好了

1.整形归类

整型家族:char、unsigned char、signed char //对于char来说,标准里并不默认其为有符号还是无符号的,这个结果取决于编译器。在计算机中,我们实际上可以用整形数据来模拟定点数运算。

short ( signed short [int] )unsigned short [int]                   
int ( signed int )unsigned int                      
long ( signed long [int] )unsigned long [int] 

浮点数家族:

float
double

构造类型:数组类型

结构体类型 struct
枚举类型 enum
联合类型 union 

指针类型
空类型

2.整型在内存中的存储

  1. 整型在内存中以补码的形式存储,浮点数则没有补码之说,它只需要规定指数与尾数。
    原因有三:其一,使用补码可以将符号位和数值域统一处理;其二,加法和减法可以统一处理(cpu只有加法器);其三,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
  2. 数据存储的大小端模式 小端字节序存储:数据的低字节存到低地址处,高字节存到高地址处。
    大端字节序存储:数据的低字节存到高地址处,高字节存到低地址处。

存在不同字节序存储模式的原因:因为在计算机系统中是以字节做单位的,每个地址单元对应一个字节,一个字节有8个比特位。不过在c语言中,除了具有一个字节(8b)的char类型外,还有2个字节(16b)的short型、4个字节(32b)的int型等,而且对于位数大于8的处理器,由于寄存器宽度大于一个字节,所以就必然存在如何安排多个字节的问题。这就是小端存储模式与大端存储模式出现的原因。

例如对于一个short类型的x数据,在内存中的地址为0x0010,其值为0x1122,那么0x11是x的高字节,0x22是x的低字节。对于大端存储模式,0x11放在低地址的0x0010中,0x22放在高地址的0x0011中。对于小端存储模式则相反。

关于大端小端字节序

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值