C语言基础(八)- 进制转化、计算机补码、位运算符

KinglyJn      2013-02-26

进制转化

  • 一个数字的大小本质上都是表示状态数的多少
  • 数字的表示可以用不同的进制
  • 十进制转r进制:整数部分–除r取余,直至商0,余数倒置即可,小数部分–乘r取整,直至积为0,整数正序排列即可
  • 二进制转10进制:8421码


补码的相关知识

在介绍补码之前先来认识其他的一些二进制码:
1、原码:
也叫符号—绝对值码,最高位0表示正、1表示负,其余二进制是该数字的绝对值的二进制位
如-5的原码是10101, 原码简单易懂,但是它加减复杂,存在加减乘除四种运算,增加了CPU的复杂度
还有就是源码制下0的表示不唯一,所以源码在计算机中从来不使用。

2、反码:
对原码每一位取反,在计算机中基本无使用

3、移码:
表示数值平移n位,(n称为移码量),移码主要用于浮点数阶码的存储

以上为认识补码的相关背景知识。
那么什么是补码呢?为什么要引入补码?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

补码的特性:

  • 一个整数的原码与其补码相加,和为模
  • 对一个整数的补码再求补码,等于该整数自身
  • 补码的正零与负零表示方法相同

通过源码求补码:

[+73]补 = 01001001
[-73]补 = 100000000 - 01001001 = 10110111

[+1]补 = 00000001
[-1]补 = 100000000 - 00000001 = 11111111

[+127] = 01111111
[-127] = 100000000 - 01111111 = 10000001

综上:
1. 整数的补码与其原码相同
2. 0的补码仍然为0
3. 负数的补码可以通过其正数的原码“取反加一”,并且最高符号位也参与运算得到

扩展:
根据补码的定义,可以证明:
[X]补 + [Y]补 = [X+Y]补
[X]补 - [Y]补 = [X-Y]补
这表明,两个补码加减的结果也是补码,而且在运算时,符号位可同数值部分作为一个整体参加运算,如果符号位有进位则舍弃进位。

计算机中的加减运算:
如:4-6=?
                          0000 0100
+ 0000 0110-->1111 1001-->1111 1010
-----------------------------------
                          1111 1110 (所得结果为补码,符号位为负)-->0000 0001-->0000 0010
故最终结果为 -2

[注] 一个数的补码为(1111 1110),求其数值?
     分析:最高位为1,则该数肯定为负数,并且我们知道“补码的补码就是其对应的非负数值”,求得0000 0010,
     故这个数的数值为 -2。


程序演示:

/**
* 计算机二进制运算程序演示
*/ 

# include <stdio.h>
int main() {
    int a = 0;
    short int i = -3;
    int j = -3;
    long int k = -3;
    char m = 'A';
    int n = 0XFFFFFFE1; //11111111111111111111111111100001 //负数最高符号位均补1

    printf("%#X\n",a); //0
    printf("%#X\n",i); //0XFFFFFFFD
    printf("%#X\n",j); //0XFFFFFFFD
    printf("%#X\n",k); //0XFFFFFFFD
    printf("%#X\n",m); //0X41
    printf("%d\n",n);  //-31 
    return 0;
}


常见的位运算符

  • 按位与&
  • 按位或|
  • 按位取反~
  • 按位异或^
  • 按位左移和按位右移 << >>
/*
 5&7=5
 5&-7=1
 5|7=7
 5|-7=-3
 ~5=-6
 ~7=6
 5^7=2
 5^-7=-4
 5<<1=10
 -7<<1=-14
 5>>1=2
 -7>>1=-4
 */

# include <stdio.h>

int main() {
    printf("5&7=%d\n", 5&7); //5的二进制补码是...0101,7的二进制补码是...0111,两者相与后补码变为...0101,输出十进制结果为5
    printf("5&-7=%d\n", 5&-7); //5的二进制补码为00000101,-7的二进制补码为11111001,5&-7=00000001,即输出结果为1
    
    printf("5|7=%d\n", 5|7); //5的二进制补码为00000101,7的二进制补码为00000111,5|7=00000111,即输出结果为7
    printf("5|-7=%d\n", 5|-7); //5的二进制补码为00000101,-7的二进制补码为11111001,5|-7=,结果的补码为11111101,是个负数,结果为-3
    
    printf("~5=%d\n", ~5);  //5的二进制补码为00000101,则~5=11111010,是个负数,结果为-6
    printf("~7=%d\n", ~-7); //-7的二进制补码为11111001,则~-7=00000110,结果为6
    
    printf("5^7=%d\n", 5^7); //5的二进制补码为00000101,7的二进制补码为00000111,5^7=00000010,结果为2
    printf("5^-7=%d\n", 5^-7); //5的二进制补码为00000101,-7的二进制补码为11111001,5^-7=111111100,结果为-4
    
    printf("5<<1=%d\n", 5<<1); //5的二进制补码为00000101,5<<1=00001010,结果为10
    printf("-7<<1=%d\n", -7<<1); //-7的二进制补码为11111001,-7<<1=11110010,结果为-14
    
    printf("5>>1=%d\n", 5>>1); //5的二进制补码为00000101,5>>1=00000010,结果为2
    printf("-7>>1=%d\n", -7>>1); //-7的二进制补码为11111001,-7>>1=11111100,结果为-4
    
    return 0;
}

Tags:


Share: