凌云的博客

行胜于言

整数表示

分类:data| 发布时间:2025-01-29 22:11:00

整型数据类型

C 支持多种整型数据类型——表示有限范围的整数。

C 和 C++ 都支持有符号(默认)和无符号数。 Java 只支持有符号数。

无符号和二进制补码编码

假设有一个整数数据类型有 w 位。 我们可以将向量写成 x ,表示整个向量,或者写成 [xw-1,xw-2,...,x0],表示向量中的每一位。 把 x 看做一个写成二进制表示的数,我们就获得了 x 的无符号表示。

我们用一个函数 B2Uw 来表示这种形式:

B2Uw ( x ) i=0 w-1 x i 2 i 等式 2.1

符号 ≐ 表示左手边被定义为等于右手边。 函数 B2Uw 将一个长度为 w 的 0、1 串映射到非负整数。 它的最小值是用位向量 [0,0,...,0] 表示,也就是整数 0,而它的最大值是用位向量 [1,1,...,1] 表示,也就是整数值 UMaxw i=0 w-1 2i = 2w -1

因此函数 B2Uw 能够被定义为一个映射 B2Uw:{0, 1}w→{0,...,2w-1}。

注意 B2Uw 是一个双射——对于每一个长度为 w 的位向量,都有一个唯一的值与之对应;反过来,在 0~2w-1 之间的每一个整数都有一个唯一的长度为 w 的位向量二进制表示与之对应。

最常见的有符号数的计算机表示方式是二进制补码形式。 它将位的最高有效位解释为负权。 我们用函数 B2Tw(表示 “二进制到二进制补码”,长度为 w)来表示这种解释:

B2Tw ( x ) - xw-1 2w-1 + i=0w-2 xi 2i 等式 2.3

最高有效位也称为符号位。当被置为 1 时,表示值为负,而当被设置为 0 时,值为非负。 它能表示的最小值是位向量 [1,0,...,0],其整数值为 TMin≐-2w-1。 而最大值是位向量 [0,1,...,1],其整数值为: TMaxw i=0 w-2 x i 2 i = 2 w-1 -1

同样地 B2Tw 也是一个双射,B2Tw:{0, 1}w→{-2w-1,...,2w-1-1},对于可表示范围内的每个位模式都有一个唯一的整数与之对应。

下表展示了一些“有趣的”数字

字长 w
8163264
UMaxw0xFF
255
0xFFFF
65 535
0xFFFFFFFF
4 294 967 295
0xFFFFFFFFFFFFFFFF
18 446 744 073 709 551 615
TMaxw0x7F
127
0x7FFF
32 767
0x7FFFFFFF
2 147 483 647
0x7FFFFFFFFFFFFFFF
9 223 372 036 854 775 807
TMinw0x80
-128
0x8000
-32 768
0x80000000
-2 147 483 648
0x8000000000000000
-9 223 372 036 854 775 808
-10xFF0xFFFF0xFFFFFFFF0xFFFFFFFFFFFFFFFF
00x000x00000x000000000x0000000000000000

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

既然 B2Uw 和 B2Tw 都是双射,它们就有明确定义的逆映射。 将 U2Bw 定义为 B2Uw-1,而将 T2Bw 定义为 B2Tw-1

考虑函数 U2Tw(x)≐B2Tw(U2Bw(x)),其输入是一个 0~2w-1 之间的值,得到一个 -2w-1~2w-1-1之间的值,这两个数由相同的位模式。

比较等式 2.1 和 2.2,我们可以发现对于位模式 x,计算 B2Uw ( x ) - B2Tw ( x )= xw-1 ( 2w-1 - -2w-1 )= xw-1 2w 。 得到 B2Uw ( x ) = x w-1 2w + B2Tw ( x ) ,令 x= B2Tw ( x ) ,有:

B2Uw ( T2Bw (x) )= T2Uw (x)= x w-1 2w +x 等式 2.5

在 x 的二进制补码表示中,位 xw-1 决定了 x 是否为负,得到:

T2U w (x) = { x + 2 w , x<0 x,x0 等式 2.6

当将一个有符号数映射为它相应的无符号数是,负数就被转换成了大的正数,而非负数保持不变。

我们推导一个无符号数 x 和与之对应的有符号数 U2Tw(x) 之间的关系。 令 x = B2U w ( x ) ,我们有

B2T w ( U2B w (u) )= U2T w (u)= - u> w-1 2 w +u 等式 2.7

在 x 的无符号表示中,位 xw-1 决定了 x 是否大于或者等于 2w-1,得到:

U2T w (u) = { u , u< 2 w-1 u - 2 w ,u 2 w-1 等式 2.8

函数 U2T 把大于 2w-1-1 的数字转换为负值。

C 中的有符号与无符号数

C 标准没有指定有符号数的表示,但是几乎所有的机器都使用二进制补码。

C 允许无符号数和有符号数之间转换。原则是基本的位表示保持不变。 因此在一台二进制补码机器上,当从无符号数转换为有符号数时,效果就是应用函数 U2Tw,而从有符号数转换为无符号数时,就是应用函数 T2Uw,其中 w 表示数据类型的位数。

C 执行一个运算时,如果它的一个运算数是有符号的而另一个是无符号的,那么 C 会隐含地将有符号参数强制转换为无符号数,并假设这两个数都是非负的。

下表展示了 32 位机器上 C 的升级规则(promotion rule)的效果:

表达式 类型 求值
0==0U 无符号 1
-1<0 有符号 1
-1<0U 无符号 0*
2147483647>-2147483647-1 有符号 1
2147483647U>-2147483647-1 无符号 0*
2147483647>(int)2147483648U 有符号 1*
-1>-2 有符号 1
(unsigned) -1 > -2 无符号 1

扩展一个数字的表示

要将一个无符号整数转换为一个更大的数据类型,我们只要简单地在表示开头添加 0。 这种运算被称为零扩展。 要将一个补码数字转换为一个更大的数字类型,规则是执行一个符号扩展,在表示中添加最高有效位的值。 如果原始值为 [xw-1,xw-2,...,x0],那么扩展后的表示就为 [xw-1,...,xw-1,xw-1,xw-2,...,x0]。

如何证明符号扩展工作正确呢? 我们需要证明 B2Tw+k([xw-1,...,xw-1,xw-1,xw-2,...,x0])=B2Tw([xw-1,xw-2,...,x0]),为了证明这个表达式,我们只需要证明:B2Tw+1([xw-1,xw-1,xw-2,...,x0])=B2Tw([xw-1,xw-2,...,x0]),然后通过归纳法即可证明原式。

用等式 2.4 展开左手边的表达式:

B2Tw+1 ([ x w-1 , x w-1 , x w-2 ,..., x 0 ]) = -x w-1 2 w + i=0 w-1 x i 2 i = -x w-1 2 w + x w-1 2 w-1 + i=0 w-1 x i 2 i = -x w-1 ( 2 w - 2 w-1 ) + i=0 w-2 x i 2 i = -x w-1 2 w-1 + i=0 w-2 x i 2 i = B2T w ([ x w-1 , x w-2 ,..., x 0 ])

截断数字

将一个 w 位的数 x =[ xw-1, xw-2,..., x0 ] 截断为 k 位时,我们会丢弃高 w-k 位,得到一个位向量: x =[ xk-1, xk-2,..., x0 ] 。 截断一个数字可能会改变它的值——溢出的一种形式。 对于一个无符号数字 x,截断它到 k 位的结果就相当于计算 x mod 2k。 通过应用模运算到等式 2.1 就可以得到:

B2Uw ([ xw-1, xw-2,..., x0 ])mod 2k= [ i=0 w-1 x i 2 i ]mod 2k = [ i=0 k-1 x i 2 i ]mod 2k = i=0 k-1 x i 2 i = B2Uk ([ xk-1, xk-2,..., x0 ])

对于一个二进制补码数字 x,相似的推理表明 B2Tw ([ xw-1, xw-2,..., x0 ])mod 2k = B2Tk ([ xk-1, xk-2,..., x0 ])

截断的结果有如下等式:

B2Uk[ xk-1, xk-2,..., x0 ]= B2Uw[ xw-1, xw-2,..., x0 ]mod 2k

等式 2.9

B2Tk[ xk-1, xk-2,..., x0 ]= U2Tk( B2Tw[ xw-1, xw-2,..., x0 ]mod 2k)

等式 2.10