《深入理解计算机系统》2.2整数表示

 
 整数的表示

整数表示

整数的数据类型

C语言中不同字长的机器和编译器会分配不同字节大小.
long类型是唯一与机器相关的.

32位机器上C语言的整数数据类型的典型取值范围
负数的取值范围比正数大1

C data typeMinimumMaximum
char−128127
unsigned char0255
short [ int ]−32,76832,767
unsigned short [ int ]065,535
int−2,147,483,6482,147,483,647
unsigned [ int ]04,294,967,295
long [ int ]−2,147,483,6482,147,483,647
unsigned long [ int ]04,294,967,295
long long [ int ]−9,223,372,036,854,775,8089,223,372,036,854,775,807
unsigned long long [ int ]018,446,744,073,709,551,615

64位机器上C语言的整数数据类型的典型取值范围
负数的取值范围比正数大1

C data typeMinimumMaximum
char−128127
unsigned char0255
short [ int ]−32,76832,767
unsigned short [ int ]065,535
int−2,147,483,6482,147,483,647
unsigned [ int ]04,294,967,295
long [ int ]−9,223,372,036,854,775,8089,223,372,036,854,775,807
unsigned long [ int ]018,446,744,073,709,551,615
long long [ int ]−9,223,372,036,854,775,8089,223,372,036,854,775,807
unsigned long long [ int ]018,446,744,073,709,551,615

C语言的整数数据类型的保证的取值范围
取值范围是对称的

C data typeMinimumMaximum
char−128127
unsigned char0255
short [ int ]−32,76732,767
unsigned short [ int ]065,535
int−32,76732,767
unsigned [ int ]065,535
long [ int ]−2,147,483,6472,147,483,647
unsigned long [ int ]04,294,967,295
long long [ int ]−9,223,372,036,854,775,8079,223,372,036,854,775,807
unsigned long long [ int ]018,446,744,073,709,551,615

补充:C/C++支持有符号和无符号,Java只支持有符号

无符号数的编码

 用

函数把一个位向量变成10进制数



无符号数的最大值为: ,所以无符号的取值范围是

补码编码

计算机表示负数通常是补码形式

把一个有符号的二进制装换成10进制

一个二进制除了符号位把剩下的位取反得到反码,再在末尾+1,得到补码
比如:1011

  1. 除了符号位取反:1100
  2. 末尾+1:1101
  3. 符号数决定这个数字是负数,后三位决定这个数的绝对值大小为5
  4. 那么这个数为-5
    补码编码的取值范围为:

由于0是属于非复数的那么,表示正数的数就少了一个

机器数用补码表示的好处

原码简单,适用于乘除运算,但用原码表示的数进行加减法运算比较复杂。
补码,减法运算可以用加法来实现,例如 [X-Y]补 = [X]补 +[-Y]补,
而且,数的符号位也可以参与运算,便于运算结果的正负及是否溢出判断。
因此在计算机中大都采用补码来进行加减及乘除运算。
(不仅是整数,小数亦可用补码表示)

确定大小的整数类型

有某个确定大小的表现编码据类型非常重要
例如
让数据类型与协议指定的数据类型兼容是非常重要的

Java要求补码表示,取值与《64位机器上C语言的整数数据类型的典型取值范围 》一样。单字节用byte,没有long long。

反码与原码

反码公式

原码公式

 

有符号与无符号间的转换

这节讲的是无符号数与有符号数直接装换造成的结果。

C语言中将short int 转换成unsight short,会改变数值而不改变位模式
比如
-12345(补码) 二进制:1100 1111 1100 0111
转换成无符号
53191(无符号) 二进制:1100 1111 1100 0111

有符号转换无符号公式


无符号转换有符号公式

总的来说对于w位的数字

  • 有符号变无符号
    • 正数不变
    • 负数会加上2^w
  • 无符号变有符号
    • 如果数字小于2^(w-1),不变
    • 如果数字大于2^(w-1),减2^w

运算时,运算符两边如果一个是有符号数,一个是无符号数,那么有符号数会自动转换成无符号.这种转换在逻辑运算中将显得不直观

 

 

例子

这个例子不是用C/C++,是C#,C#也具有完备的类型系统

最重要的是我懒得开IDE(这里用的工具CShell,C#交互式编程工具),下图中Int16,代表16位表示的整型

有符号转换为无符号

 

无符号变有符号

 

 

无符号与有符号计算

 

因为a+b的结果有可能超过16位范围,所以数据类型不仅变为有符号,而且是32位的。

 

 

扩展一个数字的位表示

 

零扩展

将一个无符号的数转换成一个跟大范围的数据类型,只要在开头加0

符号扩展

将补码数字扩展一个更大范围的数据类型,只要在前面添加最高有效位的值的副本,即最高位为0就添0为1就添1

比如1010 四位的数字扩展到6位就是111010

 

对于将short类型数字变成unsigned int 时,先扩展再从有符号变成无符号

比如short类型的-1,其二进制是16个1,符号扩展后变成32个1,最终结果是32位整型的最大值

截断数字

公式

 

无符号数如果经过运算变成负数,在计算机中会被认为是一个很大的无符号数.这种特性可能成为计算机的安全隐患.为了防止这种问题,绝不使用无符号

补充

移码

补码表示的真负数,在比较时候很不直观。
比如
010101,101011
容易认为后者较大,但事实相反

所谓移码就是对于w位的补码,给它加上2w2w。即可,这可以算是用“无符号表示有符号”。这样之后就能很直观的比较两个移码的大小。

移码会再浮点数的阶码再见到

 
comments powered by Disqus