0
点赞
收藏
分享

微信扫一扫

C语言中整数不同形式的表示与转换

醉东枫 2022-01-10 阅读 19

C语言整数不同形式的表示与转换

通常来说,用来编码整数有两种不同的方式

  • 一种只能表示非负数,即无符号数
  • 另一种能表示负数、零和正数,即有符号数

无符号数的编码

无符号数只能表示非负数,当所有位全为0是表示的值为0,其他情况均表示的是正数

其定义如下:

对向量 x → = [ x w − 1 , x w − 2 , . . . , x 0 ] \overrightarrow{x}=[x_{w-1},x_{w-2},...,x_{0}] x =[xw1,xw2,...,x0]而言,其无符号数编码的值为:
B 2 U w ( x → ) ≐ ∑ i = 0 w − 1 x i w i B2U_w(\overrightarrow{x})\doteq \sum^{w-1}_{i=0}{x_iw^i} B2Uw(x )i=0w1xiwi

例子:
B 2 U 4 ( [ 0001 ] ) = 0   ⋅ 2 3 + 0   ⋅ 2 2 + 0 ⋅ 2 1 + 1 ⋅ 2 0 = 0 + 0 + 0 + 1 = 1 B 2 U 4 ( [ 0101 ] ) = 0   ⋅ 2 3 + 1   ⋅ 2 2 + 0 ⋅ 2 1 + 1 ⋅ 2 0 = 0 + 4 + 0 + 1 = 5 B 2 U 4 ( [ 1011 ] ) = 1   ⋅ 2 3 + 0   ⋅ 2 2 + 1 ⋅ 2 1 + 1 ⋅ 2 0 = 8 + 0 + 2 + 1 = 11 B 2 U 4 ( [ 1111 ] ) = 1   ⋅ 2 3 + 1   ⋅ 2 2 + 1 ⋅ 2 1 + 1 ⋅ 2 0 = 8 + 4 + 1 + 1 = 15 \begin{aligned} &B2U_4([0001])=0\ \cdot 2^3+0\ \cdot 2^2+0\cdot 2^1+1\cdot 2^0=0+0+0+1=1 \\ &B2U_4([0101])=0\ \cdot 2^3+1\ \cdot 2^2+0\cdot 2^1+1\cdot 2^0=0+4+0+1=5 \\ &B2U_4([1011])=1\ \cdot 2^3+0\ \cdot 2^2+1\cdot 2^1+1\cdot 2^0=8+0+2+1=11 \\ &B2U_4([1111])=1\ \cdot 2^3+1\ \cdot 2^2+1\cdot 2^1+1\cdot 2^0=8+4+1+1=15 \\ \end{aligned} B2U4([0001])=0 23+0 22+021+120=0+0+0+1=1B2U4([0101])=0 23+1 22+021+120=0+4+0+1=5B2U4([1011])=1 23+0 22+121+120=8+0+2+1=11B2U4([1111])=1 23+1 22+121+120=8+4+1+1=15

有符号数的编码

最常见的有符号数的计算机表示方式就是补码(two 's complement)形式

在这个定义中,将字的最好有效位解释为负权(negative weight)

补码的定义如下

对向量 x → = [ x w − 1 , x w − 2 , . . . , x 0 ] \overrightarrow{x}=[x_{w-1},x_{w-2},...,x_{0}] x =[xw1,xw2,...,x0]而言,其补码编码的值为:
B 2 T w ( x → ) ≐ − x w − 1 2 w − 1 + ∑ i = 0 w − 1 x i w i B2T_w(\overrightarrow{x})\doteq -x_{w-1}2^{w-1}+ \sum^{w-1}_{i=0}{x_iw^i} B2Tw(x )xw12w1+i=0w1xiwi

例子(请与上面的无符号数的例子对照看):
B 2 T 4 ( [ 0001 ] ) = − 0   ⋅ 2 3 + 0   ⋅ 2 2 + 0 ⋅ 2 1 + 1 ⋅ 2 0 = 0 + 0 + 0 + 1 = 1 B 2 T 4 ( [ 0101 ] ) = − 0   ⋅ 2 3 + 1   ⋅ 2 2 + 0 ⋅ 2 1 + 1 ⋅ 2 0 = 0 + 4 + 0 + 1 = 5 B 2 T 4 ( [ 1011 ] ) = − 1   ⋅ 2 3 + 0   ⋅ 2 2 + 1 ⋅ 2 1 + 1 ⋅ 2 0 = − 8 + 0 + 2 + 1 = − 5 B 2 T 4 ( [ 1111 ] ) = − 1   ⋅ 2 3 + 1   ⋅ 2 2 + 1 ⋅ 2 1 + 1 ⋅ 2 0 = − 8 + 4 + 2 + 1 = − 1 \begin{aligned} &B2T_4([0001])=-0\ \cdot 2^3+0\ \cdot 2^2+0\cdot 2^1+1\cdot 2^0=0+0+0+1=1 \\ &B2T_4([0101])=-0\ \cdot 2^3+1\ \cdot 2^2+0\cdot 2^1+1\cdot 2^0=0+4+0+1=5 \\ &B2T_4([1011])=-1\ \cdot 2^3+0\ \cdot 2^2+1\cdot 2^1+1\cdot 2^0=-8+0+2+1=-5 \\ &B2T_4([1111])=-1\ \cdot 2^3+1\ \cdot 2^2+1\cdot 2^1+1\cdot 2^0=-8+4+2+1=-1 \\ \end{aligned} B2T4([0001])=0 23+0 22+021+120=0+0+0+1=1B2T4([0101])=0 23+1 22+021+120=0+4+0+1=5B2T4([1011])=1 23+0 22+121+120=8+0+2+1=5B2T4([1111])=1 23+1 22+121+120=8+4+2+1=1

补码的取值范围:

补码所能表示的最小值为 [ 10...0 ] [10...0] [10...0](也就是除了最高位符号位为1外其他全为0),其表示的值为 T M i n w = − 2 w − 1 TMin_w=-2^{w-1} TMinw=2w1

补码所能表示的最大值是 [ 01...1 ] [01...1] [01...1](也就是除了最高位符号位为0外其他全为1),其表示的值为 T M a x w = ∑ i = 0 w − 2 2 i = 2 w − 1 − 1 TMax_w=\sum^{w-2}_{i=0}{2^i}=2^{w-1}-1 TMaxw=i=0w22i=2w11

故补码所能表示的范围为 [ T M i n w , T M a x w ] = [ − 2 w − 1 , 2 w − 1 − 1 ] [TMin_w,TMax_w]=[-2^{w-1},2^{w-1}-1] [TMinw,TMaxw]=[2w1,2w11]

例子:

以编码字长为4为例
T M i n 4 = B 2 T 4 ( [ 1000 ] ) = − 2 3 = − 8 T M a x 4 = B 2 T 4 ( [ 0111 ] ) = 2 2 + 2 1 + 2 0 = 4 + 2 + 1 = 7 \begin{aligned} &TMin_4=B2T_4([1000])=-2^3=-8\\ &TMax_4=B2T_4([0111])=2^2+2^1+2^0=4+2+1=7 \end{aligned} TMin4=B2T4([1000])=23=8TMax4=B2T4([0111])=22+21+20=4+2+1=7

有符号数与无符号数之间的转换

对于大多数C语言的实现来说,对这个问题的回答都是从位级角度来看的

比如说,考虑如下代码:

short v = 12345;
short mv = -v;
unsigned short uv = (unsigned short) mv;
printf("v = %d, mv = %d, uv = %u", v, mv, uv);

在一台采用补码的机器上,上述代码会产生如下输出:

v = 12345 , m v = − 12345 , u v = 53191 v = 12345,mv = -12345,uv = 53191 v=12345mv=12345uv=53191

将其转换为二进制表示如下图,我们可以看到在将一个数转换为其相反数表示形式时,其位模式发生了改变,而在进行强制类型转换的时候,位模式并没有发生变化,只是改变了解释这些位的方式,从下图中也可以看到, − 12345 -12345 12345的16位补码表示与 53191 53191 53191的16位无符号表示是完全一样的。将short强制类型转换为unsigned short改变数值,但不改变位表示。

image-20220109212917131

再来看一个例子:

unsigned u = 4294967295u;    // 4294967295u为最大的32位无符号数
int tu = (int) u;
printf("u = %u, tu = %d", u, tu);

同样的,在一台采用补码的机器上,上述代码会产生如下输出

u = 4294967295 u , t u = − 1 u = 4294967295u, tu = -1 u=4294967295u,tu=1

从图2-14(在上面)可以看出,对于32位字长来说,无符号形式的 4294967295 4294967295 4294967295和补码形式的 − 1 -1 1的位模式是一模一样的。

同样的,将unsigned强制类型转换位int,底层的位表示不变

对于大多数C语言的实现,处理同样字长的有符号数和无符号数之间相互转换的一般规则是:数字可能会改变,但是位模式不会变

从第一个例子可以看出来 T 2 U 16 ( − 12345 ) = 53191 T2U_{16}(-12345)=53191 T2U16(12345)=53191,并且 U 2 T 16 ( 53191 ) = − 12345 U2T_{16}(53191)=-12345 U2T16(53191)=12345。也就是说,十六进制表示写作 0 x C F C 7 0xCFC7 0xCFC7的16位位模式既是-12345的补码表示,又是53191的无符号表示。同时注意 12345 + 53191 = 65363 = 2 16 12345+53191=65363=2^{16} 12345+53191=65363=216。类似地,对于第二个例子来说,也有如下关系 T 2 U 32 ( − 1 ) = 4294967295 T2U_{32}(-1)=4294967295 T2U32(1)=4294967295,并且 U 2 T 32 ( 4294967295 ) = − 1 U2T_{32}(4294967295)=-1 U2T32(4294967295)=1。也就是说,无符号表示中的 U M a x UMax UMax有着和补码表示的-1相同的位模式,我们在这两个数之间也能看到这种关系: 1 + U M a x w = 2 w 1+UMax_w=2^w 1+UMaxw=2w这个属性可以推广到给定位模式的两个数值(补码和无符号数)之间的关系

通过上述这些例子,我们可以得到如下关系:

补码转换为无符号数的规则:

对满足 T M i n w ≤ x ≤ T M a x w TMin_w\le x \le TMax_w TMinwxTMaxw x x x有:
T 2 U w ( x ) = { x + 2 w , x<0 x , x <= 0 T2U_w(x)=\begin{cases} x+2^w, &\text{x<0}\\ x,&\text{x <= 0} \end{cases} T2Uw(x)={x+2w,x,x<0x <= 0
对上式可以如下理解,当补码为负数时,其符号位为1,在计算其表示的数值时,最高位也就是符号位对于总数值的贡献为 − 2 w − 1 -2^{w-1} 2w1,但是当其转换位无符号数时,其最高位的贡献为 2 w − 1 2^{w-1} 2w1,二者的差值为 2 w − 1 − ( − 2 w − 1 ) = 2 w 2^{w-1}-(-2^{w-1})=2^w 2w1(2w1)=2w,因此如果补码表示的是负数,转换为无符号数时需要加 2 w 2^w 2w

例如 T 2 U 16 ( − 12345 ) = 53191 T2U_{16}(-12345)=53191 T2U16(12345)=53191,由于 − 12345 < 0 -12345<0 12345<0,因此其转换为无符号是要加上 2 16 = 65363 2^{16}=65363 216=65363,则计算得到的无符号数为 − 12345 + 2 16 = − 12345 + 65363 = 53191 -12345+2^{16}=-12345+65363=53191 12345+216=12345+65363=53191

无符号数转换为补码的规则:

对满足 0 ≤ u ≤ U M a x w 0\le u \le UMax_w 0uUMaxw u u u有:
U 2 T w ( x ) = { u , x<=TMax u − 2 w , x > TMax U2T_w(x)=\begin{cases} u, &\text{x<=TMax}\\ u-2^w,&\text{x > TMax} \end{cases} U2Tw(x)={u,u2w,x<=TMaxx > TMax
理解上式时请对照着补码转换为无符号数的解释看,如果可以的话请尽可能自己按照上面的方法推一下,以确保自己是真的理解了

总结

不论是有符号数还是无符号数,我们都需要将其编码的规则牢记于心,这样哪怕忘了转换的规则,我们只需要知道在转换的时候位模式并为发生变化,只是对于相同的二进制数值按照不同的方式进行解析而已。

最后看一下两种模式相互转换时,其不同的位模式范围的对应关系:

  • 对于非负数来说,其在两种解析方式下表示的值是一样的
  • 对于负数来说,两种解析方式下只是将其符号位的1按照不同的方式对待
    • 在有符号数模式中,符号位的1对于数值的贡献为$-2^{w-1} $
    • 在无符号数模式中,符号位的1对于数值的贡献为 2 w − 1 2^{w-1} 2w1
  • 二者相互转换的时候只需要加或者减差值 2 w 2^{w} 2w即可

image-20220109224947345

举报

相关推荐

0 条评论