首页 > 代码库 > 重要:原码、反码、补码...

重要:原码、反码、补码...

涉及计算机运算中的底层运算,所以一步步来。

一、pascal中的整数类型

Type           Range                                                 Size in bytes
Byte           0 .. 255                                              1
Shortint       -128 .. 127                                           1
Word           0 .. 65535                                            2
Integer        -32768 .. 32767                                       2
Longword       0 .. 4294967295                                       4
Longint        -2147483648 .. 2147483647                             4
QWord          0 .. 18446744073709551615                             8
Int64          -9223372036854775808 .. 9223372036854775807           8
 
整数有占1、2、4、8字节的,分为无符号与有符号。有符号的整数比无符号的常用。
有符号的整数与内存的约定是补码的形式。数据在内存中以补码形式存储,运算也以补码形式运算,运算结果也是补码。
int64与qword不是顺序类型,不能作为循环控制变量。
word经常被翻译成“字”,是占两个字节的无符号整数类型。
Dword是longword的别名,意思是double word,两个字是4字节。
Qword是四个字。带word的都是些无符号整数

运行以下程序,加深印象:

program test;begin  writeln(sizeof(byte));     //1  writeln(sizeof(shortint)); //1  writeln(sizeof(word));     //2  writeln(sizeof(integer));  //2  writeln(sizeof(longword)); //4  writeln(sizeof(longint));  //4  writeln(sizeof(qword));    //8  writeln(sizeof(int64));    //8  writeln(MaxLongint); //取得longint的最大整数值end.
View Code

 

二、处理负值时,采用补码

P44 补码中“补”的含义,有关同余定理。

初看有点难理解,说清楚了并不难理解。(以下省略五百字,上课时再说明)

这个代码,有助于理解P45 图2

//45program test;var  i:longint;  b:shortint;begin  b:=7;  for i:=1 to 16 do begin    write( b:4, space(4) );    writeln( binstr(b,4) );    dec(b);  end;end.
View Code

 

三、正数与负数的转换方法

正数转换成负数:

//47-1program test;var  i:shortint;begin  i:=%00000001; //以二进制形式输入变量值  writeln( i ); //以十进制形式输出  writeln( binstr(i,8) ); //以二进制形式输出  i:=not(i); //取反,即得到 ones complement,或称一补数  writeln( binstr(i,8) ); //一补数以二进制形式输出  inc(i); // +1,加一后,得到 twos complement,或称二补数,就是补码  writeln( i ); //以十进制形式输出  writeln( binstr(i,8) ); //以二进制形式输出end.
View Code

负数转换成正数:

//47-2program test;var  i:shortint;begin  i:=%11111100; //这是个负数  writeln( i ); //以十进制形式输出  writeln( binstr(i,8) ); //以二进制形式输出  i:=not(i); //取反,即得到 ones complement,或称一补数  writeln( binstr(i,8) ); //一补数以二进制形式输出  inc(i); // +1,加一后,得到 twos complement,或称二补数,就是补码  writeln( i ); //以十进制形式输出  writeln( binstr(i,8) ); //以二进制形式输出end.
View Code

 

有个现象观察到没有?取反加1,可以不断进行下去。。

//47-2program test;var  i:shortint;begin  i:=%11111100; //这是个负数  writeln( i ); //以十进制形式输出  writeln( binstr(i,8) ); //以二进制形式输出  i:=not(i); //取反,即得到 ones complement,或称一补数  writeln( binstr(i,8) ); //一补数以二进制形式输出  inc(i); // +1,加一后,得到 twos complement,或称二补数,就是补码  writeln( i ); //以十进制形式输出  writeln( binstr(i,8) ); //以二进制形式输出  i:=not(i)+1; writeln( i );  i:=not(i)+1; writeln( i );  i:=not(i)+1; writeln( i );  i:=not(i)+1; writeln( i );  //...end.
View Code

 

四、原码、反码、补码、移码、负补

看着头晕不?其实相当简单。

1、原码

事先确定数据的位长,即二进制的位数。因为内存以字节为单位,一字节为八位,所以位长是八的倍数。

当不够位长时,前面用0补足。但如果是负数,最高位用1补足。

其中最高位为符号位:正数为0,负数为1。

以位长为八为例子:

+11 的原码为:0000 0011

-11 的原码为: 1000 0011

2、反码

在原码的基础上,最高一位为符号位,不变,其余各位取反。所谓取反,就是not(...),即0成1,1成0。

+11 的反码为:0000 0011

-11 的反码为:1111 1100

3、补码

在反码的基础上,加一,就得到补码。

+11 的补码为:0000 0011

-11 的补码为:1111 1101

可以看到,正数的原、反、补码都一样。

4、移码

移码最简单了,不管正负数,只要将其补码的符号位取反即可。

+11 的移码为:1000 0011

-11 的移码为:0111 1101

5、负补

对补码的每一位(包括符号位)求反,然后最低位加一。

+11 的补码为:0000 0011,对每一位求反,为:1111 1100,最低位加一,为:1111 1101

-11 的补码为:1111 1101,对第一位求反,为:0000 0010,最低位加一,为:0000 0011

将一个数的补码,与负补码加起来,你会发现什么?

请看代码,仅以负数举例:

program test;var  i,j,k:shortint;begin  i:=-%11; //二进制的 -11  writeln( binstr(i,8) ); //以二进制形式输出。  //观察输出,可以发现,内存中,以补码的形式储存数据  j:=i xor %10000000;  writeln( binstr(j,8) ); //移码  k:=not(i)+1;  writeln( binstr(k,8) ); //负补码  writeln( binstr(i+k,8) ); //补码+负补码,产生上溢end.
View Code

 

接下来,请看下一章:整数类型,如同时钟。

重要:原码、反码、补码...