重要:原码、反码、补码...
涉及计算机运算中的底层运算,所以一步步来。
一、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.
二、处理负值时,采用补码
P44 补码中“补”的含义,有关同余定理。
初看有点难理解,说清楚了并不难理解。(以下省略五百字,上课时再说明)
这个代码,有助于理解P45 图2
//45 program 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.
三、正数与负数的转换方法
正数转换成负数:
//47-1 program test; var i:shortint; begin i:=%00000001; //以二进制形式输入变量值 writeln( i ); //以十进制形式输出 writeln( binstr(i,8) ); //以二进制形式输出 i:=not(i); //取反,即得到 one's complement,或称一补数 writeln( binstr(i,8) ); //一补数以二进制形式输出 inc(i); // +1,加一后,得到 two's complement,或称二补数,就是补码 writeln( i ); //以十进制形式输出 writeln( binstr(i,8) ); //以二进制形式输出 end.
负数转换成正数:
//47-2 program test; var i:shortint; begin i:=%11111100; //这是个负数 writeln( i ); //以十进制形式输出 writeln( binstr(i,8) ); //以二进制形式输出 i:=not(i); //取反,即得到 one's complement,或称一补数 writeln( binstr(i,8) ); //一补数以二进制形式输出 inc(i); // +1,加一后,得到 two's complement,或称二补数,就是补码 writeln( i ); //以十进制形式输出 writeln( binstr(i,8) ); //以二进制形式输出 end.
有个现象观察到没有?取反加1,可以不断进行下去。。
//47-2 program test; var i:shortint; begin i:=%11111100; //这是个负数 writeln( i ); //以十进制形式输出 writeln( binstr(i,8) ); //以二进制形式输出 i:=not(i); //取反,即得到 one's complement,或称一补数 writeln( binstr(i,8) ); //一补数以二进制形式输出 inc(i); // +1,加一后,得到 two's 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.
四、原码、反码、补码、移码、负补
看着头晕不?其实相当简单。
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.
接下来,请看下一章:整数类型,如同时钟。