一、整型数据类型
C 语言支持多种整型数据类型——表示有限范围的整数。
每种类型都能用关键字来指定大小 ,这些关键字包括 char 、 short 、long ,同时还可以指示被表示的数字是非负数(声明为 unsigned ),或者可能是负数(默认)。
以下为 64 位 程序上 C 语言整型数据类型的典型取值范围:
C 数据类型 最小值 最大值 [signed] char -128 127 unsigned char 0 255 short -32 768 32 767 unsigned short 0 65 535 int -2 147 483 648 2 147 483 647 unsigned 0 4 294 967 295 long -9 223 372 036 854 775 808 9 223 372 036 854 775 807 unsigned long 0 18 446 744 073 709 551 615 int32_t -2 147 483 648 2 147 483 647 uint32_t 0 4 294 967 295 int64_t -9 223 372 036 854 775 808 9 223 372 036 854 775 807 uint64_t 0 18 446 744 073 709 551 615
二、无符号数的编码
假设有一个整数数据类型有 w w w 位。我们可以将位向量写成 x ⃗ \vec{x} x ,表示整个向量,或者写成 [ x w − 1 x_{w-1} x w − 1 , x w − 2 x_{w-2} x w − 2 , ... , x 0 x_{0} x 0 ],表示向量中的每一位。把 x ⃗ \vec{x} x 看做一个二进制表示的数,就获得了x ⃗ \vec{x} x 的无符号表示。
在这个编码中,每个位 x i x_{i} x i 都取值为 0 或 1,后一种取值意味着数值 2 i 2^{i} 2 i 应为数字值的一部分。我们用一个函数 B 2 U w B2U_{w} B 2 U w ( Binary to Unsigned 的缩写,长度为 w w w )来表示:
原理 :无符号数编码的定义 。
对向量 x ⃗ \vec{x} x =[ x w − 1 x_{w-1} x w − 1 , x w − 2 x_{w-2} x w − 2 , ... , x 0 x_{0} x 0 ] :
B 2 U w ( x ⃗ ) = ˙ ∑ i = 0 w − 1 x i 2 i B2U_{w}(\vec{x}) \dot{=} \sum_{i=0}^{w-1}x_{i}2^{i} B 2 U w ( x ) = ˙ ∑ i = 0 w − 1 x i 2 i
在这个等式中,符号 “= ˙ \dot{=} = ˙ ” 表示左边被定义为等于右边。函数 B 2 U w B2U_{w} B 2 U w ,将一个长度为 w w w 的 0、1 串映射到非负整数。
举一个示例,下面几种情况下 B 2 U B2U B 2 U 给出的从位向量到整数的映射:
B 2 U 4 ( [ 0001 ] ) = 0 ⋅ 2 3 + 0 ⋅ 2 2 + 0 ⋅ 2 1 + 1 ⋅ 2 0 = 0 + 0 + 0 + 1 = 1 B2U_{4}([0001]) = 0 \cdot 2^{3} + 0 \cdot 2^{2} + 0 \cdot 2^{1} + 1 \cdot 2^{0} = 0 + 0 + 0 + 1 = 1 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 B2U_{4}([0101]) = 0 \cdot 2^{3} + 1 \cdot 2^{2} + 0 \cdot 2^{1} + 1 \cdot 2^{0} = 0 + 4 + 0 + 1 = 5 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 B2U_{4}([1011]) = 1 \cdot 2^{3} + 0 \cdot 2^{2} + 1 \cdot 2^{1} + 1 \cdot 2^{0} = 8 + 0 + 2 + 1 = 11 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 + 2 + 1 = 15 B2U_{4}([1111]) = 1 \cdot 2^{3} + 1 \cdot 2^{2} + 1 \cdot 2^{1} + 1 \cdot 2^{0} = 8 + 4 + 2 + 1 = 15 B 2 U 4 ([ 1111 ]) = 1 ⋅ 2 3 + 1 ⋅ 2 2 + 1 ⋅ 2 1 + 1 ⋅ 2 0 = 8 + 4 + 2 + 1 = 15
w w w =4 的无符号数示例,当二进制表示中位 i i i 为 1,数值就会相应加上 2 i 2^{i} 2 i :
让我们来考虑一下 w w w 位所能表示的值的范围:
最小值 是用位向量 [ 00 … 0 ] [00…0] [ 00 … 0 ] 表示,也就是整数值0。
而最大值 是用位向量 [ 11 … 1 ] [11…1] [ 11 … 1 ] 表示,也就是整数值 U M a x w = ˙ ∑ l i m i t s i = 0 w − 1 2 i = 2 w − 1 UMax_{w} \dot{=} \sum_limits{i=0}^{w-1}{2^i} = 2^{w}-1 U M a x w = ˙ ∑ l imi t s i = 0 w − 1 2 i = 2 w − 1 ,以 4 位数情况为例,U M a x 4 = B 2 U 4 ( [ 1111 ] ) = 2 4 − 1 = 15 UMax_{4} = B2U_{4}([1111]) = 2^{4}-1 = 15 U M a x 4 = B 2 U 4 ([ 1111 ]) = 2 4 − 1 = 15 。因此,函数 B 2 U w B2U_{w} B 2 U w 能够被定义为一个映射 B 2 U : { 0 , 1 } w → { 0 , . . . , 2 w − 1 } B2U:\{0,1\}^{w} \rightarrow \{0, ...,2^{w}-1\} B 2 U : { 0 , 1 } w → { 0 , ... , 2 w − 1 } 。
无符号数的二进制表示有一个很重要的属性,也就是每个介于 0 ∼ 2 w − 1 0 \sim 2^{w}-1 0 ∼ 2 w − 1 之间的数都有唯一一个 w w w 位的值编码。例如,十进制值 11 作为无符号数,只有一个 4 位的表示,即 [ 1011 ] [1011] [ 1011 ] 。
我们用数学原理来重点讲述它,先表述原理再解释。
原理:无符号数编码的唯一性 。
函数 B 2 U w B2U_{w} B 2 U w 是一个双射。
数学术语 双射 是指一个函数 f f f 有两面:它将数值 x x x 映射为数值 y y y ,即 y = f ( x ) y=f(x) y = f ( x ) ,但它也可以反向操作,因为对每一个 y y y 而言,都有唯一一个数值 x x x 使得 f ( x ) = y f(x)=y f ( x ) = y 。这可以用 反函数 f − 1 f^{-1} f − 1 来表示,在本例中,即 x = f − 1 ( y ) x = f^{-1}(y) x = f − 1 ( y ) 。函数 B 2 U w B2U_{w} B 2 U w ,将每一个长度为 w w w 的位向量都映射为 0 ∼ 2 w − 1 0 \sim 2^{w}-1 0 ∼ 2 w − 1 之间的一个唯一值;反过来,我们称其为 U 2 B w U2B_{w} U 2 B w ,(即“无符号数到二进制”),在 0 ∼ 2 w − 1 0 \sim 2^{w}-1 0 ∼ 2 w − 1 之间的每一个整数都可以映射为一个唯一的长度为 w w w 的位模式。
三、补码编码
对于许多应用,我们还希望表示负数值。
最常见的有符号数的计算机表示方式就是补码 ( two ' s - complement )形式。在这个定义中,将字的最高有效位解释为负权 ( negative weight )。我们用函数 B 2 T w B2T_{w} B 2 T w 。( Binary to Two ' s - complement 的缩写,长度为 w w w )来表示:
原理:补码编码的定义 。
对向量 x ⃗ \vec{x} x =[ x w − 1 x_{w-1} x w − 1 , x w − 2 x_{w-2} x w − 2 , ... , x 0 x_{0} x 0 ] :
B 2 T w ( x ⃗ ) = ˙ − x w − 1 2 w − 1 + ∑ l i m i t s i = 0 w − 2 x i 2 i B2T_{w}(\vec{x}) \dot{=} -x_{w-1}{2^{w-1}} + \sum_limits{i=0}^{w-2}x_{i}2^{i} B 2 T w ( x ) = ˙ − x w − 1 2 w − 1 + ∑ l imi t s i = 0 w − 2 x i 2 i
最高有效位 x w − 1 x_{w-1} x w − 1 也称为符号位 ,它的“权重“为 − 2 w − 1 -2_{w-1} − 2 w − 1 ,是无符号表示中权重的负数。符号位被设置为 1 时,表示值为负,而当设置为 0 时,值为非负。
这里来看一个示例,下面几种情况下 B 2 T B2T B 2 T 给出的从位向量到整数的映射:
B 2 T 4 ( [ 0001 ] ) = − 0 ⋅ 2 3 + 0 ⋅ 2 2 + 0 ⋅ 2 1 + 1 ⋅ 2 0 = 0 + 0 + 0 + 1 = 1 B2T_{4}([0001]) = - 0 \cdot 2^{3} + 0 \cdot 2^{2} + 0 \cdot 2^{1} + 1 \cdot 2^{0} = 0 + 0 + 0 + 1 = 1 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 B2T_{4}([0101]) = -0 \cdot 2^{3} + 1 \cdot 2^{2} + 0 \cdot 2^{1} + 1 \cdot 2^{0} = 0 + 4 + 0 + 1 = 5 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 B2T_{4}([1011]) = -1 \cdot 2^{3} + 0 \cdot 2^{2} + 1 \cdot 2^{1} + 1 \cdot 2^{0} = -8 + 0 + 2 + 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 B2T_{4}([1111]) = -1 \cdot 2^{3} + 1 \cdot 2^{2} + 1 \cdot 2^{1} + 1 \cdot 2^{0} = -8 + 4 + 2 + 1 = -1 B 2 T 4 ([ 1111 ]) = − 1 ⋅ 2 3 + 1 ⋅ 2 2 + 1 ⋅ 2 1 + 1 ⋅ 2 0 = − 8 + 4 + 2 + 1 = − 1
w w w =4 的补码示例,把位 3 作为符号位,因此当它为 1 时,对数值的影响是 − 2 3 = − 8 -2^{3}=-8 − 2 3 = − 8 。(这个权重在图中用带向左箭头的条表示):
让我们来考虑一下 w w w 位补码所能表示的值的范围。它能表示的最小值是位向量 [ 10...0 ] [10...0] [ 10...0 ] (也就是设置这个位为负权,但是清除其他所有的位),其整数值为 T M i n w = ˙ − 2 w − 1 TMin_{w} \dot{=} -2^{w-1} TM i n w = ˙ − 2 w − 1 。而最大值是位向量 [ 01...1 ] [01...1] [ 01...1 ] (清除具有负权的位,而设置其他所有的位),其整数值为 TMax_{w} \dot{=} \sum_\limits{i=0}^{w-2}2^{i}=2^{w-1}-1 。以长度为 4 为例,我们有 T M i n 4 = B 2 T 4 ( [ 1000 ] ) = − 2 3 = − 8 TMin_{4}=B2T_{4}([1000])=-2^{3}=-8 TM 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 TMax_{4}=B2T_{4}([0111])=2^{2}+ 2^{1}+2^{0}=4+2+1=7 TM a x 4 = B 2 T 4 ([ 0111 ]) = 2 2 + 2 1 + 2 0 = 4 + 2 + 1 = 7 。
我们可以看出 B 2 T w B2T_{w} B 2 T w 是一个从长度为 w {w} w 的位模式到 T M i n w TMin_{w} TM i n w ,和 T M a x w TMax_{w} TM a x w 之间数字的映射,写作 B 2 T w B2T_{w} B 2 T w :{ 0 , 1 } w → { T m i n w , . . . , T M a x w } \{0,1\}^{w} \to \{Tmin_{w},...,TMax_{w}\} { 0 , 1 } w → { T mi n w , ... , TM a x w } 。同无符号表示一样,在可表示的取值范围内的每个数字都有一个唯一的 w {w} w 位的补码编码。这就导出了与无符号数相似的补码数原理:
原理:补码编码的唯一性 。
函数 B 2 T w B2T_{w} B 2 T w 是一个 双射 。
我们定义函数 T 2 B w T2B_{w} T 2 B w (即“补码到二进制”)作为 B 2 T w B2T_{w} B 2 T w 的反函数。也就是说,对于每个数 x {x} x ,满足 T M i n w ≤ x ≤ T M a x w TMin_{w} \leq x \leq TMax_{w} TM i n w ≤ x ≤ TM a x w ,则 T 2 B w ( x ) T2B_{w}(x) T 2 B w ( x ) 是 x {x} x 的(唯一的)w {w} w 位模式。
下表展示了不同字长,几个重要数字 的位模式和数值(前三个给出的是可表示的整数的范围):
字长 w w w 数 8 16 32 64 U M a x w UMax_{w} U M a x w 0xFF 255 0×FFFF 65 535 0xFFFFFFFF 4 294 967 295 0xFFFFFFFFFFFFFFFF 18 446 744 073 709 551 615 T M i n w TMin_{w} TM i n w 0x80 -128 0x8000 -32 768 0x80000000 -2 147 483 648 0x8000000000000000 -9223 372 036 854775 808 T M a x w TMax_{w} TM a x w 0x7F 127 0x7FFF 32 767 0x7FFFFFFF 2 147 483 647 0x7FFFFFFFFFFFFFFF 9 223 372 036 854 775 807 -1 0 0xFF 0×00 0xFFFF 0×0000 0xFFFFFFFF 0x00000000 0xFFFFFFFFFFFFFFFF 0x0000000000000000
关于这些数字,有几点值得注意:
第一,补码的范围是不对称的 :∣ T M i n ∣ = ∣ T M a x ∣ + 1 |{TMin}|=|{TMax}|+1 ∣ TM in ∣ = ∣ TM a x ∣ + 1 ,也就是说, T M i n TMin TM in 没有与之对应的正数。正如我们将会看到的,这导致了补码运算的某些特殊的属性,并且容易造成程序中细微的错误 。之所以会有这样的不对称性,是因为一半的位模式(符号位设置为 1 的数)表示负数,而另一半(符号位设置为 0 的数)表示非负数。因为 0 是非负数,也就意味着能表示的整数比负数少一个 。
第二,最大的无符号数值刚好比补码的最大值的两倍大一点 : U M a x w = 2 T M a x w 十 1 UMax_{w}=2TMax_{w}十1 U M a x w = 2 TM a x w 十 1 。 补码表示中所有表示负数的位模式在无符号表示中都变成了正数。上表也给出了常数 -1 和 0 的表示。注意 -1 和 U M a x UMax U M a x 有同样的位表示 —— 一个全 1 的串。数值 0 在两种表示方式中都是全 0 的串。
如果希望代码具有最大可移植性 ,能够在所有可能的机器上运行,那么除了所示的那些范围之外,我们不应该假设任何可表示的数值范围,也不应该假设有符号数会使用何种特殊的表示方式。
关于整数数据类型的取值范围和表示, Java 标准是非常明确 的。它要求采用补码表示。举个例子,在 Java 中,单字节数据类型称为 byte ,而不是 char 。这些非常具体的要求都是为了保证无论在什么机器上运行 , Java 程序都能表现地完全一样 。
四、有符号数和无符号数之间的转换
C 语言允许在各种不同的数字数据类型之间做强制类型转换。
short intv = -12345 ;
unsigned short uv = (unsigned short )v;
printf ("v = %d, uv = %u\n" , v, uv);
ν=-12345 , uν = 53191
对于大多数 C 语言的实现,处理同样字长的有符号数和无符号数之间相互转换的一般规则是:数值 可能会改变 ,但是位模式不变 。
我们考虑无符号与补码表示之间互相转换 的结果:
对于在范围 0 ≤ x ≤ T M a x w 0 \leq x \leq TMax_{w} 0 ≤ x ≤ TM a x w 之内的值 x x x 而言,我们得到 T 2 U w ( x ) = x T2U_{w}(x)=x T 2 U w ( x ) = x 和 U 2 T w ( x ) = x U2T_{w}(x)=x U 2 T w ( x ) = x 。也就是说,在这个范围内的数字有相同的无符号和补码表示。
对于这个范围以外的数值,转换需要加上或者减去 2 w 2^{w} 2 w 。例如,我们有 T 2 U w ( − 1 ) = − 1 + 2 w = U M a x w T2U_{w}(-1)=-1+2^{w}=UMax_{w} T 2 U w ( − 1 ) = − 1 + 2 w = U M a x w —— 最靠近 0 的负数映射为最大的无符号数。
在另一个极端,我们可以看到 T 2 U w ( T M i n w ) = − 2 w − 1 + 2 w = 2 w − 1 = T M a x w + 1 T2U_{w}(TMin_{w})=-2^{w-1}+2^{w}=2^{w-1}=TMax_{w}+1 T 2 U w ( TM i n w ) = − 2 w − 1 + 2 w = 2 w − 1 = TM a x w + 1 —— 最小的负数映射为一个刚好在补码的正数范围之外的无符号数。
根据下图所示,我们能看到 T 2 U 16 ( − 12345 ) = 65563 + ( − 12345 ) = 53191 T2U_{16}(-12 345)=65 563+(-12 345)=53 191 T 2 U 16 ( − 12345 ) = 65563 + ( − 12345 ) = 53191 。
12 345 和 -12 345 的补码表示,以及 53 191 的无符号表示。注意后面两个数有相同的位 表示。
五、扩展一个数字的位表示
一个常见的运算是在不同字长的整数之间转换 ,同时又保持数值不变 。当然,当目标数据类型太小以至于不能表示想要的值时,这根本就是不可能的。然而,从一个较小 的数据类型转换到一个较大 的类型,应该总是可能的。
要将一个无符号数转换为一个更大的数据类型,我们只要简单地在表示的开头添加 0 这种运算被称为零扩展 ( zero extension ),表示原理如下:
原理:无符号数的零扩展 。
定义宽度为 w w w 的位向量 u ⃗ = [ u w − 1 , u w − 2 , . . . , u 0 ] \vec{u} = [ u_{w-1} , u_{w-2} , ... , u_{0} ] u = [ u w − 1 , u w − 2 , ... , u 0 ] 和宽度为 w ′ w\prime w ′ 的位向量 u ⃗ ′ = [ 0 , . . . , 0 , u w − 1 , u w − 2 , . . . , u 0 ] \vec{u}\prime = [ \color{SkyBlue}0 , \color{Black}... , \color{SkyBlue}0 , \color{Black}u_{w-1} , u_{w-2} , ... , u_{0} ] u ′ = [ 0 , ... , 0 , u w − 1 , u w − 2 , ... , u 0 ] ,其中 w ′ > w w\prime > w w ′ > w 。则 B 2 U w ( u ⃗ ) = B 2 U w ′ ( u ′ ⃗ ) B2U_{w}(\vec{u})=B2U_{w\prime}(\vec{u\prime}) B 2 U w ( u ) = B 2 U w ′ ( u ′ )
要将一个补码数字转换为一个更大的数据类型,可以执行一个符号扩展 ( sign extension ),在表示中添加最高有效位的值,表示为如下原理。我们用蓝色标出符号位 x w − 1 \color{SkyBlue}x_{w-{1}} x w − 1 来突出它在符号扩展中的角色。
原理:补码数的符号扩展 。
定义宽度为 w w w 的位向量 x ⃗ = [ x w − 1 , x w − 2 , . . . , x 0 ] \vec{x} = [ \color{SkyBlue}x_{w-1} , \color{Black}x_{w-2} , ... , x_{0} ] x = [ x w − 1 , x w − 2 , ... , x 0 ] 和宽度为 w w w 的位向量 x ⃗ ′ = [ x w − 1 , . . . , x w − 1 , x w − 1 , x w − 2 , x 0 ] \vec{x}\prime = [ \color{SkyBlue}x_{w-1} , \color{Black}... , \color{SkyBlue}x_{w-1} , \color{SkyBlue}x_{w-1} , \color{Black}x_{w-2} ,x_{0} ] x ′ = [ x w − 1 , ... , x w − 1 , x w − 1 , x w − 2 , x 0 ] ,其中 w ′ > w w\prime > w w ′ > w 。则 B 2 T w ( x ⃗ ) = B 2 T w ′ ( x ′ ⃗ ) B2T_{w}(\vec{x})=B2T_{w\prime}(\vec{x\prime}) B 2 T w ( x ) = B 2 T w ′ ( x ′ )
六、截断数字
假设我们不用额外的位来扩展一个数值,而是减少表示一个数字的位数。例如下面代码中这种情况:
int x = 53191 ;
short sx= (short ) x;
int y = sx;
当我们把 × 强制类型转换为 short 时,我们就将 32 位的 int 截断为了 16 位的 short int。
就像前面所看到的,这个 16 位的位模式就是 -12345 的补码表示。当我们把它强制类型转换回 int 时,符号扩展把高 16 位设置为 1,从而生成 -12345 的 32 位补码表示。
当将一个 w w w 位的数 x ⃗ = [ x w − 1 , x w − 2 , . . . , x 0 ] \vec{x}=[x_{w-1} , x_{w-2} , ... , x_{0}] x = [ x w − 1 , x w − 2 , ... , x 0 ] 截断为一个 k k k 位数字时,我们会丢弃高 w − k w-k w − k 位,得到一个位向量 x ⃗ ′ = [ x k − 1 , x k − 2 , . . . , x 0 ] \vec{x}\prime=[ x_{k-1} , x_{k-2} , ... , x_{0} ] x ′ = [ x k − 1 , x k − 2 , ... , x 0 ] 。截断一个数字可能会改变它的值 —— 溢出的一种形式。对于一个无符号数,我们可以很容易得出其数值结果。
原理:截断无符号数 。
令 x ⃗ \vec{x} x 等于位向量 [ x w − 1 , x w − 2 , . . . , x 0 ] [x_{w-1} , x_{w-2} , ... , x_{0}] [ x w − 1 , x w − 2 , ... , x 0 ] ,而 x ⃗ ′ \vec{x}\prime x ′ 是将其截断为 k k k 位的结果: x ⃗ ′ = [ x k − 1 , x k − 2 , . . . , x 0 ] \vec{x}\prime=[x_{k-1} , x_{k-2} , ... , x_{0}] x ′ = [ x k − 1 , x k − 2 , ... , x 0 ] 。令 x = B 2 U w ( x ⃗ ) x=B2U_{w}(\vec{x}) x = B 2 U w ( x ) , x ′ = B 2 U k ( x ⃗ ′ ) x\prime=B2U_{k}(\vec{x}\prime) x ′ = B 2 U k ( x ′ ) 。则 x ⃗ ′ = x m o d 2 k \vec{x}\prime=x \bmod 2^{k} x ′ = x mod 2 k 。该原理背后的直觉就是所有被截去的位其权重形式都为 2 i 2^{i} 2 i ,其中 i ≥ k i \geq k i ≥ k ,因此,每一个权在取模操作下结果都为零。
原理:截断补码数值 。
令 x ⃗ \vec{x} x 等于位向量 [ x w − 1 , x w − 2 , . . . , x 0 ] [x_{w-1} , x_{w-2} , ... , x_{0}] [ x w − 1 , x w − 2 , ... , x 0 ] ,而 x ⃗ ′ \vec{x}\prime x ′ 是将其截断为 k k k 位的结果: x ⃗ ′ = [ x k − 1 , x k − 2 , . . . , x 0 ] \vec{x}\prime=[x_{k-1} , x_{k-2} , ... , x_{0}] x ′ = [ x k − 1 , x k − 2 , ... , x 0 ] 。
令 x = B 2 U w ( x ⃗ ) x=B2U_{w}(\vec{x}) x = B 2 U w ( x ) , x ′ = B 2 T k ( x ⃗ ′ ) x\prime=B2T_{k}(\vec{x}\prime) x ′ = B 2 T k ( x ′ ) 。则 x ′ = U 2 T k ( x m o d 2 k ) x\prime=U2T_{k}(x \bmod 2^{k}) x ′ = U 2 T k ( x mod 2 k ) 。
在这个公式中,x m o d 2 k x \bmod 2^{k} x mod 2 k 将是 0 到 2 k − 1 2^{k}-1 2 k − 1 之间的一个数。对其应用函数 U 2 T k U2T_{k} U 2 T k ,产生的效果是把最高有效位 x k − 1 x_{k-1} x k − 1 的权重从 2 k − 1 2^{k-1} 2 k − 1 转变为 − 2 k − 1 -2^{k-1} − 2 k − 1 。
举例来看,将数值 x = 53191 x=53 191 x = 53191 从 int 转换为 short 。由于 2 16 = 65536 ≥ x 2^{16}=65 536 \geq x 2 16 = 65536 ≥ x ,我们有 x m o d 2 16 = x x \bmod 2^{16}=x x mod 2 16 = x 。但是,当我们把这个数转换为 16 位的补码时,我们得到 x ⃗ ′ = 53191 − 65536 = − 12345 \vec{x}\prime=53 191-65 536=-12 345 x ′ = 53191 − 65536 = − 12345
六、结束语
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶 。