2、数据表示
约 4668 字大约 16 分钟
2025-06-18
原码表示又称为带符号的绝对值表示
定点整数 真值x=+1011 [x]原= 0,1011 真值x=-1010 [x]原=1,1010 定点小数 真值x=+0.1111 [x]原= 0.1111 真值x=-0.0101 [x]原=1.0101
- 优点 表示方法简单直观
- 缺点 真值0在原码中有两种不同的表示 符号位不能直接参与运算
原码在计算机中目前仅仅用于表示浮点数的尾码
补码
模的概念 模(或称模数)是一个数值计量系统的计量范围,记作mod或M。 只要确定了“模”,就可找到一个与负数等价的正数来代替此负数,该正数就是负数的补数。 超过计量范围的数都应该自动舍弃模数。 如: 时间表示(时)采用12进制 6+13=19≡7(mod12)
补数的特点 一个负数可用它的正补数替代,而这个正补数可以用模数加上负数本身求得 一个整数和一个负数互为补数时,它们绝对值之和即为模数 整数的补数即该正数本身
补数的作用 把减法用加法实现 符号位也可以直接参与运算 符号位参与运算时最高位的进位舍去即为结构 但相比于原码比较复杂 目前计算机中普遍采用补码表示有符号定点整数,例如:C语言中char、short、int、long型整数都是采用补码进行表示的
a-b=[a]补+[-b]补
正数的补码:符号位为0,数值位就是它本身 负数的补码:等于模数加上该负数本身,而模数就是最高位进位的位权值 对于计算机字长为n位,求定点整数(负)的补码:[x]补=2n+x
0在补码中只有一种表示,因此补码可以比原码多表示一个数
反码
正数的补码和原码一样 负数的补码是符号位不变数值位取反得到的结果即为反码,反码再末位+1即可得到补码 反码通常用来作为原码求补或者补码求原码的中间过渡
正数的反码:符号位为0,数值位就是它本身 负数的反码:符号位为1,数值位就是真值数值位取反 符号位参加运算时最高位的进位需要加到运算结果的末尾(循环进位)即为运算结果
移码
移码就是在真值上加一个常数2n 在数轴上,移码所表示的范围对应于真值在数轴上的范围向轴的正方向移动wn个单元 移码只用于定点整数的表示
移码的优点 真值0在移码中只有一种表示 移码保持了真值原有的大小顺序可以直接比较大小 最小帧之的移码全为0,最大真值的移码全为1,符合人们的习惯 当浮点数的阶码用移码来表示时,就能很方便地比较阶码地大小
[!tip] Title 在现代计算机中,通常用定点补码整数表示整数,用定点原码小数表示浮点数的尾数部分,用移码表示浮点数的阶码部分。
浮点数的表示
定点小数只适合用于小于1的小数
二进制浮点数可采用类似十进制科学计数法的表示方法
十进制浮点数:108.32=4.0832×102=4083.2×10−1=0.40832×10−3 二进制浮点数:110.0101=1.100101×210=1100.101×2−1=0.1100101×211(其指数也是二进制表示)
二进制表示应使用常认知的定点小数(即绝对值的大小小于1) 这样任意一个二进制数N可表示为:N=rE×M
因小数点的位置是浮动的,所以被称为浮点数
浮点数在机器中表示常为两部分组成,第一部分表示阶码E,第二部分表示尾数M都分别由二进制位构成,阶码的最高位是阶符用来表示小数点移动的方向,其他部分是阶码的数值部分 阶码的位数决定了数据表示的范围,位数越多,能表示的数据范围越大 阶码的值决定了小数点的位置 尾数的最高位是数符,用来表示位数的正负也就是整个浮点数的正负,剩余其他部分是尾数的数值部分,尾数的位数决定了数据的精度,解码长度相同时分配给尾数的位数越多,数据表示的精度就越高
阶码可采用原码、补码、反码、移码来表示 尾数可采用原码、补码、反码来表示 对应浮点数表示的范围会略有不同
尽管浮点数有效扩大了数据表示范围,但受机器字长限制,浮点数仍然存在溢出现象。 当浮点数的阶码大于最大阶码时,称为上溢,此时机器停止运算,浮点运算器件会显示溢出标志 当浮点数的阶码小于最小阶码时,称为下溢,虽然此时数据不能被精确表示,但由于发生下溢时数据的绝对值很小,通常将尾数各位强置为0,按机器0处理,此时机器可以继续运行。 当一个浮点数在正、负数区域中但并不在某个数轴刻度上时,也会出现精度溢出的问题,此时只能用近似数表示。
浮点数的规格化
110.0101=211×0.1100101=2100×0.01100101 由此可见同一浮点数可能存在多种表示形式也就是会有不同的阶码和尾数的组合 因此通常要求浮点数在数据表示时对尾数进行规格化处理,即使得尾数的最高数值位必须是一个有效值 浮点数规格化好处: 使浮点数的表示形式唯一 使浮点数的表示精度最高
对于非规格化尾数应根据其具体形式对其尾数的数值部分进行左移或右移并相应减少或增加阶码,对应的规格化方法分别称为左规或右规(向左或向右规格化)
浮点数的表示形式
浮点数的上述表示形式,既没有规定阶码和尾数的位数,也没有规定阶码和尾数采用的机器码形式(原码、反码、补码和移码)。 实际上,直到20世纪80年代初,浮点数表示形式还没有统一标准,不同厂商计算机内部浮点数表示形式可能不同。 不同体系结构的计算机之间进行数据传送或程序移植时,必须进行数据格式的转换,并且数据格式转换还会带来运算结果的不一致。 因此,美国电气及电子工程师协会(Institute of Electrical and Electronics Engineers,IEEE)于1985年发布了浮点数标准IEEE 754。 目前,几乎所有计算机都采用IEEE 754标准表示浮点数,
32位单精度浮点数对应c语言中的float型 64位双精度浮点数对应c语言中的double型
在IEEE 754 浮点数标准中,32位单精度浮点数的8位阶码尽管采用移码表示,但采用偏移常数是27−1=127,而不是标准移码的27=128。 [x]移=x+(27−1)−27≤x<27 采用偏移常数128表示的最小规格化数的倒数会发生溢出,而采用偏移常数127表示的任何一个规格化数的倒数则不会溢出。 阶码为全1、全0有特殊用途
引入无穷大数可使计算过程出现异常的情况下程序能继续执行,并且可为程序提供错误检测功能 例如非0浮点数除0的结果就是无穷大,因此非0浮点数除0不会像整型数除0一样产生严重错误
32位单精度浮点数
数值的分类 | 符号S | 阶码E | 尾数M | 真值 |
---|---|---|---|---|
正零 | 0 | 0(全0) | 0 | +0 |
负零 | 1 | 0(全0) | 0 | -0 |
非规格化正数 | 0 | 0(全0) | M≠0 | (−1)0×2−126×0.M |
非规格化负数 | 1 | 0(全0) | M≠0 | (−1)1×2−126×0.M |
正无穷大 | 0 | 255(全1) | 0 | +∞ |
负无穷大 | 1 | 255(全1) | 0 | −∞ |
无定义数(非数) | 0或1 | 255(全1) | ≠0 | NaN |
规格化正数 | 0 | 1<=E<=254 | M | (−1)0×2E−127×1.M |
规格化负数 | 1 | 1<=E<=254 | M | (−1)1×2E−127×1.M |
64位双精度浮点数 |
数值的分类 | 符号S | 阶码E | 尾数M | 真值 |
---|---|---|---|---|
正零 | 0 | 0(全0) | 0 | +0 |
负零 | 1 | 0(全0) | 0 | -0 |
非规格化正数 | 0 | 0(全0) | M≠0 | (−1)0×2−1022×0.M |
非规格化负数 | 1 | 0(全0) | M≠0 | (−1)1×2−1022×0.M |
正无穷大 | 0 | 2047(全1) | 0 | +∞ |
负无穷大 | 1 | 2047(全1) | 0 | −∞ |
无定义数(非数) | 0或1 | 2047(全1) | ≠0 | NaN |
规格化正数 | 0 | 1<=E<=2046 | M | (−1)0×2E−1023×1.M |
规格化负数 | 1 | 1<=E<=2046 | M | (−1)1×2E−1023×1.M |
一般情况下+0和-0是等价的 当尾数M不为0阶码E为全1时不管符号位是0还是1都表示NaN(not a number)无定义数(或非数) 非数用于表示00、∞∞、0×∞、负数的平方根等 部分非数NaN运算结果可能产生异常 非规格化数可用于处理阶码下溢,使得出现比最小规格数还小的数时程序也能继续进行下去
溢出
采用原码表示时
当运算结果大于能表示的最大正数时,称为正上溢;小于最小负数时。称为负上溢:两者统称上溢。由于尾数的溢出可以通过移位、增加阶码来调整。 如1.2×2n如果发生尾数溢出可以将尾数右移一位,然后阶码加一依旧可以表示出来:0.12×2n+1 只有当阶码达到最大时才无法继续表示,因此上溢的本质就是阶码大于最大阶码,这时机器会停止计算,进行中断溢出处理。
同样的当发生尾数下溢时也可以通过对尾数进行移动操作,然后阶码加1进行表示 当运算结果在0至最小正数之间时,称为正下溢;在0至最大负数之间时,称为负下溢,统称下溢。同样道理,下溢的本质是阶码小于最小阶码,这时溢出的数值绝对值非常小,通常可以将尾数各位直接强置为0,按“机器零”来处理,机器可以继续正常运行。
浮点数的规格化
由于规格化数的精度最高,所以当一个非零的浮点数不是规格化数时,应该通过左右移动尾数、并同时修改阶码的方法,将它转换为规格化数。把一个非规格化数转换成规格化数的过程,叫做规格化。规格化的本质类似于“科学计数法”的表达,通过保证尾数最高数位上是一个有效值,尽可能多地保留有效数字的尾数,从而提高精度。
- 左规:向左规格化。当运算结果尾数的最高数位不是有效位,即出现0.0...01..的形式时,需要向左规格化。左规时,尾数左移一位,阶码减1;
- 右规:向右规格化。当运算结果尾数的小数点左侧出现有效位,即整数部分不为0时,需要向右规格化。右规时,尾数右移一位,阶码加1;需要右规时,只需进行一次。
C语言中的数据类型及转换
计算机中的数据以二进制的形式存储在寄存器或存储器中。 汇编语言中的数据类型取决于指令操作码。 存储在寄存器、存储器中的操作数本身没有数据类型,对该数进行何种数据类型的操作完全取决于指令。 同一个操作数,既可以当作有符号数,也可以当作无符号数;既可以是定点数,也可以是浮点数。 而高级语言中有数据类型
数据类型转换
整型之间的类型转换
char、short、int 、long 这四种整型数据的表示范围不一样,很可能数据转换后精度缺失,此时就只能尽量保持转换前后的机器码或机器码部分相同
相同字长之间的转换
如char和unsigned char互转 char的取值范围为-128~127 unsigned char取值范围是0~255 在0~127之间的数转换后的数据与原值相同 在交集范围外: -128~-1的char转unsigned char 符号位为1表示负数,但转换后符号位也被当做数值位。转换后的数据=256+原值 128~255的unsigned char转char 转换后的最高位表示值的1被当作符号位表示负值,因此转换后的数据=原值-256
小字长转大字长
原数据为无符号类型,进行0扩展 unsigned char转short unsigned char转unsigned short 转换后在数据缺少的位前面补0,转换后的数据是相同的
原数据为有符号类型,进行符号扩展 char转short char转unsigned short 转换后在原来的8位机器码前面添加8个位变成16位机器码,补的值为原机器码符号位的取值 由于short型变量是有符号整型变量,因此编译器将16位机器码解析为补码,这样不管原机器码符号位是0还是1被解析后的数据依旧与原值相同
大字长转小字长
一般情况下编译器会把机器码截断处理,很可能会导致范围缩小,出错 转换后会从前面把数据阶段,得到后面的数据很可能会与原值不同
int、float、double之间的转换
上述三种类型数据的机器码并不相同(int型数据是32位有符号整数,用补码表示,float和double型数据分别是32位和64位浮点数,它们的阶码用移码表示,尾数用原码表示) 且表示的范围和精度也不相同 因此编译器只能保证数值尽量相等,大多数情况下只是近似值
float转double 由于ouble型数据的阶码和尾数的位数都比float型大,因此其表示范围更大、精度更高,转换后的double型数据与原float型数据的值完全相等
double转float 大数转换可能会发生溢出 高精度转换发生舍入
float/double转int 小数部分向0方向截断 大数转换可能溢出
int转float 两种类型都是32位,各自的数据组合(状态)数量相同,但二者在数轴上的数据并不完全重叠 由于float型浮点数的尾数包括隐藏位在内共2位,当int型数据的高八位(24~31位)数据为非0时,无法精确转换成24位浮点数的尾数,此时发生精度溢出
int转double double型数据的尾数包含隐藏位在内有53位,可以精确表示所有32位整数
浮点数的加减法
浮点数运算的特点,是阶码运算和尾数运算分开进行。浮点数加/减运算可以分为5步进行:
- 对阶 对阶的目的是使两个操作数的小数点位置对齐,使两个数的阶码相等。先求阶差,然后以“小阶向大阶看齐”的原则,将阶码小的尾数右移一位(基数为2),阶码加1,直到两个数的阶码相等为止。
- 尾数求和 将对阶后的尾数,按定点数加/减运算规则运算。
- 规格化 IEEE754规格化尾数的形式为+1.×.,所以当计算结果为非规格化数时,需要进行规格化处理。 左规:当结果为±0.0...01×..×时,需进行左规。尾数每左移一位,阶码减1。可能需要左规多次,直到将第一位1移到小数点左边。 右规:当结果为±1x.X..x时,出现了尾数的溢出,需进行右规。尾数右移一位,阶码加1。当尾数右移时,最高位1被移到小数点前一位作为隐藏位;当最后一位移出时,要考虑舍入。 左规一次相当于乘以2,右规一次相当于除以2;需要右规时,只需进行一次。
- 舍入 在对阶和尾数右规时,尾数右移可能会将低位丢失,影响精度,IEEE754有以下4种舍入方式:·就近舍入:舍入为最近的那个数,类似于“四舍五入”,一般被叫做“0舍1入”法;如果被舍入的值恰好是100...0形式,选择舍入为最近的偶数;·正向舍入:向+方向舍入,即取右边那个数,也叫“向上舍入”;·负向舍入:向方向舍入,即取左边那个数,也叫“向下舍入”;·截断:朝0方向舍入,即取绝对值较小的那个数。
- 溢出判断 浮点数的溢出,并不是以尾数溢出来判断的;尾数溢出可以通过右规操作得到纠正。运算结果是否溢出,主要看结果的指数是否发生了溢出,因此是由阶码来判断的。 若一个正阶码超出了最大允许值(127或1023),则发生上溢,产生异常; 若一个负阶码超出了最小允许值(-149或-1074),则发生下溢,通常把结果按机器零处理。
贡献者
版权所有
版权归属:PinkDopeyBug