Java机器数之原码反码补码

96
Showdy
0.1 2017.08.12 19:04* 字数 2642

机器数之原码反码补码

基本概念

  1. 在计算机中,一串数码作为一个整体来处理或运算的,称为一个计算机字,简称字。字通常分为若干个字节(每个字节一般是8位)。在存储器中,通常每个单元存储一个字,因此每个字都是可以寻址的。字的长度用位数来表示。

    在计算机的运算器、控制器中,通常都是以字为单位进行传送的。字出现在不同的地址其含义是不相同。例如,送往控制器去的字是指令,而送往运算器去的字就是一个数。

  2. 字长

    字长是指计算机的每个字所包含的位数。字长是CPU的主要技术指标之一,指的是CPU一次能并行处理的二进制位数,字长总是8的整数倍,通常PC机的字长为16位(早期),32位,64位。

  3. 字节:

    字节是指一小组相邻的二进制数码。通常是8位作为一个字节。它是构成信息的一个小单位,并作为一个整体来参加操作,比字小,是构成字的单位。在微型计算机中,通常用多少字节来表示存储器的存储容量。

  4. 机器数:

    机器数(computer number)是将符号"数字化"的数,是数字在计算机中的二进制表示形式。机器数有2个特点:一是符号数字化,二是其数的大小受机器字长的限制.

    数的符号数值化。实用的数据有正数和负数,由于计算机内部的硬件只能表示两种物理状态(用0和1表示),因此实用数据的正号“+”或负号“-”,在机器里就用一位二进制的0或1来区别。通常这个符号放在二进制数的最高位,称符号位,以0代表符号“+”,以1代表符号“-”。

    二进制的位数受机器设备的限制。机器内部设备一次能表示的二进制位数叫机器的字长,一台机器的字长是固定的。字长8位叫一个字节(Byte),机器字长一般都是字节的整数倍,如字长8位、16位、32位、64位。

    如一个十进制的数为+7,计算机的字长为16,那么该数字的机器数为0000 0000 0111;如果是-7,则表示为1000 0000 000 0111;

  5. 真值:

    因为有符号占据一位,数的形式值就不等于真正的数值,带符号位的机器数对应的数值称为机器数的真值。 例如二进制真值数-011011,它的机器数为 1011011。

    0000 1100(机)=+0000 1100(真)=+12; 1000 1100(机)=-0000 1100(真)=-12;

机器码的原码反码补码的三种表示形式

  1. 原码:

    将数的真值形式中“+”号用“0”表示,“-”号用“1”表示时,叫做数的原码形式,简称原码。 若计算机的字长为n位, X数字为正时,[X]原=X; X为负值时,将X的绝对值|X|的符号位变为1即可.

     如(字长为8)
     [+1]原=0000 0001; [-1]原=1000 0001; 8位二进制的范围为[-127,127];  
    
  2. 反码:

    反码正是解决符号位参与运算而产生, 正数的反码为本身, 负数的反码是其符号位不变其余位取反(~).

     [+1]=[0000 0001]原=[0000 0001]反
     [-1]=[1000 0001]原=[1111 1110]反
    
  3. 补码:

    补码是同余概念引入的,补码的表示规则也很简单:正数的补码为期本身,负数的补码为其反码再加1;
    即X为正: [X]补=[X];X为负:[X]补=[X]反+1;

     [+1]=[0000 0001]原=[0000 0001]反=[0000 0001]补
     [-1]=[1000 0001]原=[1111 1110]反=[1111 1111]补
    

原码反码补码的由来

原码表示法比较直观,它的数值部分就是该数的绝对值,而且与真值、十进制数的转换十分方便。但是它的加减法运算较复杂。当两数相加时,机器要首先判断两数的符号是否相同,如果相同则两数相加,若符号不同,则两数相减。在做减法前,还要判断两数绝对值的大小,然后用大数减去小数,最后再确定差的符号,换言之,用这样一种直接的形式进行加运算时,负数的符号位不能与其数值部分一道参加运算,而必须利用单独的线路确定和的符号位。

为了解决符号位参加运算的问题,引进反码. 将符号位参与运算:

 1-1=1+(-1)=[00000001]原+[10000001]原=[00000001]反+[11111110]反=[11111111]反=[10000000]原=-0;

使用反码时发现一个特殊值"0",会存在+0和-0两种原码即[00000000]原和[10000000]原.

为了解决0这个特殊的值,另外反码运算由于循环进位需要二次运算而引入补码.

 `1-1=1+(-1)=[00000001]原+[10000001]原=[00000001]补+[11111111]补==[10000000]补=[00000000]原=0;`

这样,+0和-0的问题就不存在,而且还可以用[1000 0000]表示-128;
-1+(-127)=[1111 1111]补+[1000 0001]补=[1000 0000]补,但计算机实际上是用-0表示-128,所以-128并没有原码和反码.

使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].

因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-231, 231-1]即[0x80000000,0x7fffffff], 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.

同余概念

同余定理:给定一个正整数m,如果两个整数a和b满足(a-b)能够被m整除,即(a-b)/m得到一个整数,那么就称整数a与b对模m同余,记作a≡b(mod m)。对模m同余是整数的一个等价关系。

假定当前时间为北京时间6点整,有一只手表却是8点整,比北京时间快了2小时,校准的方法有两种,一种是倒拨2小时,一种是正拨10小时。若规定倒拨是做减法,正拨是做加法,那么对手表来讲减2与加10是等价的,也就是说减2可以用加10来实现。这是因为8加10等于18,然而手表最大只能指示12,当大于12时12自然丢失,18减去12就只剩6了。这说明减法在一定条件下,是可以用加法来代替的。这里“12”称为“模”,10称为“-2”对模12的补数。推广到一般则有:

A – B = A + ( – B + M ) = A + ( – B )补

反码的运算规则

1.反码运算时,其符号位与数值一起参加运算。

2.反码的符号位相加后,如果有进位出现,则要把它送回到最低位去相加(循环进位)。

3.用反码运算,其运算结果亦为反码。在转换为真值时,若符号位为0,数位不变;若符号位为1,应将结果求反才是其真值。

如 x=+1101,Y=+0110,用反码计算Z=X-Y;
[01101]反+[11001]反=[01101]+[11001]+1=[00111]反;其真值Z=+0111;

采用反码运算较好的解决了原码运算所遇到的困难或问题,但由于循环进位需要二次算术相加,延长了计算时间,这同样给电路带来麻烦。而采用下述的补码运算则可避免循环进位的两次计算,同时,采用补码运算对溢出的判断也较采用反码简单的多,所以机器中的算术运算普遍采用补码运算。

补码运算规则

1.补码运算时,其符号位与数值部分一起参加运算。

2.补码的符号位相加后,如果有进位出现,要把这个进位舍去(自然丢失)。

3.用补码运算,其运算结果亦为补码。在转换为真值时,若符号位为0,数位不变;若符号位为1,应将结果求补才是其真值

如:X=+1101,Y=+0110,用补码计算Z=X-Y;
[X]补+[-Y]补=[01101]补+[11010]补=01101+11010=100111,其真值为Z=+0111;

如X=+0110,Y=+1101,用补码计算Z=X-Y;
[X]补+[-Y]补=[00110]+[10011]=[11001]补,其真值为Z=-0111.

溢出及补码溢出的判断

无论采用何种机器数,只要运算的结果大于数值设备所能表示数的范围,就会产生溢出。 溢出现象应当作一种故障来处理,因为它使结果数发生错误。异号两数相加时,实际是两数的绝对值相减,不可能产生溢出,但有可能出现正常进位;同号两数相加时,实际上是两数的绝对值相加,既可能产生溢出,也可能出现正常进位。

由于补码运算存在符号位进位自然丢失而运算结果正确的问题,因此,应区分补码的溢出与正常进位。

例如,某数字设备用5位二进制表示数,其数字范围为[-16,15],如果两数字相加减得到的数字超出该范围则溢出.如:

  1. [+9]补+[+3]补=01001+00011=01100=+12;正确
  2. [-9]补+[-3]补=10111+11101=110100=10100(符号位进位自然丢失),真值为-1100=-12;
  3. [+9]补+[12]补=01001+01100=10101,真值为-1011=-11;溢出
  4. [-9]补+[-12]补=10111+10100=101011,真值为01011=+11,溢出

一般可以用异或(^)来判断补码溢出问题(单符号位补码):
运算结果,若 Cs^Cp =0 无溢出,若 Cs^Cp =1 有溢出,
(Cs是符号位的进位,Cp是最高数值位的进位,^表示异或)

Java