精华内容
下载资源
问答
  • 尽管能查到各种文献,亲自归纳出自己体系还是更能加深对该知识理解。... 二、原码反码补码的基础概念 三、为什么要使用原码反码补码 四、原码补码反码再深入 五、数据溢出测试...

        尽管能查到各种文献,亲自归纳出自己的体系还是更能加深对该知识的理解。

        本篇文章便是在结合百度百科有关原码反码补码位运算的介绍并深度借鉴了张子秋Liquor相关文章后整理而出。
     
    目录:
        一、机器数和真值
        二、原码,反码和补码的基础概念
        三、为什么要使用原码,反码和补码
        四、原码,补码,反码再深入
        五、数据溢出测试
        、位运算的运算说明
        七、位运算的简单应用 
     
     
    一、机器数和真值
     
        机器数(computer number)是数字在计算机中的二进制表示形式
        机器数有2个特点:一是符号数字化,二是其数的大小受机器字长的限制
        比如:十进制中的+6,计算机字长为8位,转换成二进制就是00000110,如果是-6,就是10000110
        这里的00000110和10000110便是机器数
     
        因为第一位是符号位(正数该位为0,负数该位为1,0分+0和-0),所以:
            ①8位二进制数的取值范围就是:[1111 1111 , 0111 1111]
            ②机器数的形式值就不等于真正的数值。
                为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
                比如:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1
     
     
    二、原码,反码和补码的基础概念
     
        对于一个数, 计算机要使用一定的编码方式进行存储。原码, 反码, 补码是机器存储一个具体数字的编码方式
            [+1] = [00000001]原 = [00000001]反 = [00000001]补
            [-1] = [10000001]原 = [11111110]反 = [11111111]补
     
        1.原码
            原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值
        2.反码
            正数的反码是其本身
            负数的反码是在其原码的基础上, 符号位不变,其余各个位取反
        3.补码        
            正数的补码就是其本身
            负数的补码即是在反码的基础上+1
     
        由此可见,正数的原码反码补码都是自身,负数的反码,补码都无法直观看出其数值,需要转换成原码再计算其数值
     
     
    三、为什么要使用原码,反码和补码
     
        对于计算机,加减乘数已经是最基础的运算, 要设计的尽量简单,而让计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂。于是人们开始探索将符号伪参与运算,并且只保留加法的方法
     
        若用原码计算十进制减法:1-1=0,结果是不正确的:
            1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
        使用反码时,结果的真值部分正确:
            1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
        而反码的问题在于0上,反码中会有[0000 0000]原=+0和[1000 0000]原=-0两个编码表示0,于是出现了解决这一问题的补码[1000 0000]补(8位二进制机器数中,补码还能够多表示一个最低数-128=[1000 0000]补):
            1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
     
     
    四、原码,补码,反码再深入
     
        再次推荐张子秋有关原码反码补码的博客,里面还讲了同余的概念与负数取模,自己也就不摘抄了。。
        x mod y等于 x 减去 y 乘上 x与y的商的下界
        一个数的反码, 实际上是这个数对于一个膜的同余数,而这个膜并不是我们的二进制, 而是所能表示的最大值
        由于0的特殊情况, 没有办法表示128, 所以补码的取值范围是[-128, 127]
     
     
    五、数据溢出测试
     
     
    六、位运算的运算说明
     
        1. & 按位 与「AND」
            功能:对应的两个二进位 均为1 时,结果 为1,否则 为0
            例子:9&5 = 1001&0101 = 0001,即 9&5=1
            *规律:二进制中与 1& 保持原位,与  0& 为0
     
        2. | 按位 或「OR」
            功能:对应的两个二进位 只要有一个为1 时,结果 为1,否则 为0
            例子:9|5 = 1001|0101 = 1101,即 9|5=13
     
        3. ^ 按位 异或「XOR,EOR」
            功能:对应的两个二进位 不相同 为1,否则 为0
            例子:9^5 = 1001^0101 = 1100,即 9^5=12
            *规律:
                同一整数 相异或 为0,               例:5^5=0
                不同整数 相异或 结果和顺序无关,例:5^6^7 = 5^7^6
                任何数 和 0 异或 结果不变,        例:x^0 = x
                综上,x^y^x = x^x^y = 0^y = y
     
        4. ~ 按位 取反「NOR」
            功能:对整数的 每一位取反,符号也位取反「取反:0取反为1,1取反为0」
            例子:~9 = -10(因为负数是补码存储的)
                ~9=~[00001001]原=[11110110]补=[11110101]反=[10001010]原=-10
     
        5. << 左移(shl)
            格式:整数<<左移个数
            例子:x << n
            实质:x * 2n
            操作:把 x 的二进制位 向左移动 n 个单位,高位丢弃,低位补0
     
        6. >> 右移(shr)
            格式:整数>>右移个数
            例子:x >> n
            实质:x / 2n
            操作:把 x 的二进制位 向右移动 n 个单位,低位丢弃,符号位不变
            注意:符号位也跟着移动, 右移不改变整数的正负, 最后符号位要调整为原来的数值
            正数 符号位为 0, 最高位补0
            负数 符号位为 1, 最高位补1
     
     
    七、位运算的简单应用
     
        1.(& 按位 与「AND」)奇偶判断
            取模判断:a%2?printf(“奇数\n”):printf(“偶数\n”);
            与壹判断:a&1?printf(“奇数\n”):printf(“偶数\n”);
     
        2.(^ 按位 异或「XOR,EOR」)数值转换
            借助第三方变量:temp = a;a = b;b = temp;
            不借助额外空间,数学法:a = b - a;b = b - a;a = b + a;
            不借助额外空间,位运算:a = a ^ b;b = a ^ b;a = a ^ b;
     
        3.(<< 左移 和 >> 右移)优化乘除法效率
            a shl b 的值等于a乘以2的b次方
            a shr b 比如二分查找、堆的插入操作等等
     

    转载于:https://www.cnblogs.com/corvoh/p/5138033.html

    展开全文
  • 二、原码反码补码的基础概念 三、为什么要使用原码反码补码 四、原码补码反码再深入 五、数据溢出测试 六、位运算运算说明 七、位运算简单应用 一、机器数和真值 机器数...
     
    目录:
        一、机器数和真值
        二、原码,反码和补码的基础概念
        三、为什么要使用原码,反码和补码
        四、原码,补码,反码再深入
        五、数据溢出测试
        、位运算的运算说明
        七、位运算的简单应用 
     
     
    一、机器数和真值
     
        机器数(computer number)是数字在计算机中的二进制表示形式
        机器数有2个特点:一是符号数字化,二是其数的大小受机器字长的限制
        比如:十进制中的+6,计算机字长为8位,转换成二进制就是00000110,如果是-6,就是10000110
        这里的00000110和10000110便是机器数
     
        因为第一位是符号位(正数该位为0,负数该位为1,0分+0和-0),所以:
            ①8位二进制数的取值范围就是:[1111 1111 , 0111 1111]
            ②机器数的形式值就不等于真正的数值。
                为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
                比如:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1
     
     
    二、原码,反码和补码的基础概念
     
        对于一个数, 计算机要使用一定的编码方式进行存储。原码, 反码, 补码是机器存储一个具体数字的编码方式
            [+1] = [00000001]原 = [00000001]反 = [00000001]补
            [-1] = [10000001]原 = [11111110]反 = [11111111]补
     
        1.原码
            原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值
        2.反码
            正数的反码是其本身
            负数的反码是在其原码的基础上, 符号位不变,其余各个位取反
        3.补码        
            正数的补码就是其本身
            负数的补码即是在反码的基础上+1
            由此可见,正数的原码反码补码都是自身,负数的反码,补码都无法直观看出其数值,需要转换成原码再计算其数值
     
     
    三、为什么要使用原码,反码和补码
     
        对于计算机,加减乘数已经是最基础的运算, 要设计的尽量简单,而让计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂。于是人们开始探索将符号伪参与运算,并且只保留加法的方法
     
        若用原码计算十进制减法:1-1=0,结果是不正确的:
            1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
        使用反码时,结果的真值部分正确:
            1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
        而反码的问题在于0上,反码中会有[0000 0000]原=+0和[1000 0000]原=-0两个编码表示0,于是出现了解决这一问题的补码[1000 0000]补(8位二进制机器数中,补码还能够多表示一个最低数-128=[1000 0000]补):
            1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
     
     
    四、原码,补码,反码再深入
     
        x mod y等于 x 减去 y 乘上 x与y的商的下界
        一个数的反码, 实际上是这个数对于一个模的同余数,而这个膜并不是我们的二进制, 而是所能表示的最大值
        由于0的特殊情况, 没有办法表示128, 所以补码的取值范围是[-128, 127]
     
     
    五、数据溢出测试
        待补上~~~
     
    六、位运算的运算说明
     
        1. & 按位 与「AND」
            功能:对应的两个二进位 均为1 时,结果 为1,否则 为0
            例子:9&5 = 1001&0101 = 0001,即 9&5=1
            *规律:二进制中与 1& 保持原位,与  0& 为0
     
        2. | 按位 或「OR」
            功能:对应的两个二进位 只要有一个为1 时,结果 为1,否则 为0
            例子:9|5 = 1001|0101 = 1101,即 9|5=13
     
        3. ^ 按位 异或「XOR,EOR」
            功能:对应的两个二进位 不相同 为1,否则 为0
            例子:9^5 = 1001^0101 = 1100,即 9^5=12
            *规律:
                同一整数 相异或 为0,               例:5^5=0
                不同整数 相异或 结果和顺序无关,例:5^6^7 = 5^7^6
                任何数 和 0 异或 结果不变,        例:x^0 = x
                综上,x^y^x = x^x^y = 0^y = y
     
        4. ~ 按位 取反「NOR」
            功能:对整数的 每一位取反,符号也位取反「取反:0取反为1,1取反为0」
            例子:~9 = -10(因为负数是补码存储的)
                ~9=~[00001001]原=[11110110]补=[11110101]反=[10001010]原=-10
     
        5. << 左移(shl)
            格式:整数<<左移个数
            例子:x << n
            实质:x * 2n
            操作:把 x 的二进制位 向左移动 n 个单位,高位丢弃,低位补0
     
        6. >> 右移(shr)
            格式:整数>>右移个数
            例子:x >> n
            实质:x / 2n
            操作:把 x 的二进制位 向右移动 n 个单位,低位丢弃,符号位不变
            注意:符号位也跟着移动, 右移不改变整数的正负, 最后符号位要调整为原来的数值
            正数 符号位为 0, 最高位补0
            负数 符号位为 1, 最高位补1
     
     
    七、位运算的简单应用
     
        1.(& 按位 与「AND」)奇偶判断
            取模判断:a%2?printf(“奇数\n”):printf(“偶数\n”);
            与壹判断:a&1?printf(“奇数\n”):printf(“偶数\n”);
     
        2.(^ 按位 异或「XOR,EOR」)数值转换
            借助第三方变量:temp = a;a = b;b = temp;
            不借助额外空间,数学法:a = b - a;b = b - a;a = b + a;
            不借助额外空间,位运算:a = a ^ b;b = a ^ b;a = a ^ b;
     
        3.(<< 左移 和 >> 右移)优化乘除法效率
            a shl b 的值等于a乘以2的b次方
            a shr b 比如二分查找、堆的插入操作等等

    转载于:https://www.cnblogs.com/AlwaysOnLines/p/5154472.html

    展开全文
  • 在学习原码, 反码补码之前, 需要先了解机器数和真值的概念. 1、机器数 一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1. 比如...

    这种题目目的是考察计算机基础知识是否扎实。

    一. 机器数和真值

    在学习原码, 反码和补码之前, 需要先了解机器数和真值的概念.

    1、机器数

    一个数在计算机中的二进制表示形式,  叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.

    比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。

    那么,这里的 00000011 和 10000011 就是机器数。

    2、真值

    因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。

    例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

     

    二. 原码, 反码, 补码的基础概念和计算方法.

    在探求为何机器要使用补码之前, 让我们先了解原码, 反码和补码的概念.对于一个数, 计算机要使用一定的编码方式进行存储. 原码, 反码, 补码是机器存储一个具体数字的编码方式.

    1. 原码

    原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:

    [+1]原 = 0000 0001

    [-1]原 = 1000 0001

    第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:

    [1111 1111 , 0111 1111]

    [-127 , 127]

    原码是人脑最容易理解和计算的表示方式.

    2. 反码

    反码的表示方法是:

    正数的反码是其本身

    负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.

    [+1] = [00000001]原 = [00000001]反

    [-1] = [10000001]原 = [11111110]反

    可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算.

    3. 补码

    补码的表示方法是:

    正数的补码就是其本身

    负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)

    [+1] = [00000001]原 = [00000001]反 = [00000001]补

    [-1] = [10000001]原 = [11111110]反 = [11111111]补

    对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.

     

    三. 为何要使用原码, 反码和补码

    在开始深入学习前, 我的学习建议是先"死记硬背"上面的原码, 反码和补码的表示方式以及计算方法.

    现在我们知道了计算机可以有三种编码方式表示一个数. 对于正数因为三种编码方式的结果都相同:

    [+1] = [00000001]原 = [00000001]反 = [00000001]补

    所以不需要过多解释. 但是对于负数:

    [-1] = [10000001]原 = [11111110]反 = [11111111]补

    可见原码, 反码和补码是完全不同的. 既然原码才是被人脑直接识别并用于计算表示方式, 为何还会有反码和补码呢?

    首先, 因为人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的加减. (真值的概念在本文最开头). 但是对于计算机, 加减乘数已经是最基础的运算, 要设计的尽量简单. 计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了.

    于是人们开始探索 将符号位参与运算, 并且只保留加法的方法. 首先来看原码:

    计算十进制的表达式: 1-1=0

    1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2

    如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数.

    为了解决原码做减法的问题, 出现了反码:

    计算十进制的表达式: 1-1=0

    1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0

    发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在"0"这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0.

    于是补码的出现, 解决了0的符号以及两个编码的问题:

    1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原

    这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:

    (-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补

    -1-127的结果应该是-128, 在用补码运算的结果中, [1000 0000]补 就是-128. 但是注意因为实际上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示.(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的)

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

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

     

    四 原码, 反码, 补码 再深入

    计算机巧妙地把符号位参与运算, 并且将减法变成了加法, 背后蕴含了怎样的数学原理呢?

    将钟表想象成是一个1位的12进制数. 如果当前时间是6点, 我希望将时间设置成4点, 需要怎么做呢?我们可以:

    1. 往回拨2个小时: 6 - 2 = 4

    2. 往前拨10个小时: (6 + 10) mod 12 = 4

    3. 往前拨10+12=22个小时: (6+22) mod 12 =4

    2,3方法中的mod是指取模操作, 16 mod 12 =4 即用16除以12后的余数是4.

    所以钟表往回拨(减法)的结果可以用往前拨(加法)替代!

    现在的焦点就落在了如何用一个正数, 来替代一个负数. 上面的例子我们能感觉出来一些端倪, 发现一些规律. 但是数学是严谨的. 不能靠感觉.

    首先介绍一个数学中相关的概念: 同余

     

    同余的概念

    两个整数a,b,若它们除以整数m所得的余数相等,则称a,b对于模m同余

    记作 a ≡ b (mod m)

    读作 a 与 b 关于模 m 同余。

    举例说明:

    4 mod 12 = 4

    16 mod 12 = 4

    28 mod 12 = 4

    所以4, 16, 28关于模 12 同余.

     

    负数取模

    正数进行mod运算是很简单的. 但是负数呢?

    下面是关于mod运算的数学定义:

    clip_image001

    上面是截图, "取下界"符号找不到如何输入(word中粘贴过来后乱码). 下面是使用"L"和"J"替换上图的"取下界"符号:

    x mod y = x - y L x / y J

    上面公式的意思是:

    x mod y等于 x 减去 y 乘上 x与y的商的下界.

    以 -3 mod 2 举例:

    -3 mod 2

    = -3 - 2xL -3/2 J

    = -3 - 2xL-1.5J

    = -3 - 2x(-2)

    = -3 + 4 = 1

    所以:

    (-2) mod 12 = 12-2=10

    (-4) mod 12 = 12-4 = 8

    (-5) mod 12 = 12 - 5 = 7

     

    开始证明

    再回到时钟的问题上:

    回拨2小时 = 前拨10小时

    回拨4小时 = 前拨8小时

    回拨5小时= 前拨7小时

    注意, 这里发现的规律!

    结合上面学到的同余的概念.实际上:

    (-2) mod 12 = 10

    10 mod 12 = 10

    -2与10是同余的.

    (-4) mod 12 = 8

    8 mod 12 = 8

    -4与8是同余的.

    距离成功越来越近了. 要实现用正数替代负数, 只需要运用同余数的两个定理:

    反身性:

    a ≡ a (mod m)

    这个定理是很显而易见的.

    线性运算定理:

    如果a ≡ b (mod m),c ≡ d (mod m) 那么:

    (1)a ± c ≡ b ± d (mod m)

    (2)a * c ≡ b * d (mod m)

    如果想看这个定理的证明, 请看:http://baike.baidu.com/view/79282.htm

    所以:

    7 ≡ 7 (mod 12)

    (-2) ≡ 10 (mod 12)

    7 -2 ≡ 7 + 10 (mod 12)

    现在我们为一个负数, 找到了它的正数同余数. 但是并不是7-2 = 7+10, 而是 7 -2 ≡ 7 + 10 (mod 12) , 即计算结果的余数相等.

    接下来回到二进制的问题上, 看一下: 2-1=1的问题.

    2-1=2+(-1) = [0000 0010]原 + [1000 0001]原= [0000 0010]反 + [1111 1110]反

    先到这一步, -1的反码表示是1111 1110. 如果这里将[1111 1110]认为是原码, 则[1111 1110]原 = -126, 这里将符号位除去, 即认为是126.

    发现有如下规律:

    (-1) mod 127 = 126

    126 mod 127 = 126

    即:

    (-1) ≡ 126 (mod 127)

    2-1 ≡ 2+126 (mod 127)

    2-1 与 2+126的余数结果是相同的! 而这个余数, 正式我们的期望的计算结果: 2-1=1

    所以说一个数的反码, 实际上是这个数对于一个膜的同余数. 而这个膜并不是我们的二进制, 而是所能表示的最大值! 这就和钟表一样, 转了一圈后总能找到在可表示范围内的一个正确的数值!

    而2+126很显然相当于钟表转过了一轮, 而因为符号位是参与计算的, 正好和溢出的最高位形成正确的运算结果.

    既然反码可以将减法变成加法, 那么现在计算机使用的补码呢? 为什么在反码的基础上加1, 还能得到正确的结果?

    2-1=2+(-1) = [0000 0010]原 + [1000 0001]原 = [0000 0010]补 + [1111 1111]补

    如果把[1111 1111]当成原码, 去除符号位, 则:

    [0111 1111]原 = 127

    其实, 在反码的基础上+1, 只是相当于增加了膜的值:

    (-1) mod 128 = 127

    127 mod 128 = 127

    2-1 ≡ 2+127 (mod 128)

    此时, 表盘相当于每128个刻度转一轮. 所以用补码表示的运算结果最小值和最大值应该是[-128, 128].

    但是由于0的特殊情况, 没有办法表示128, 所以补码的取值范围是[-128, 127]

    本人一直不善于数学, 所以如果文中有不对的地方请大家多多包含, 多多指点!

    展开全文
  • 在学习原码, 反码补码之前, 需要先了解机器数和真值的概念. 1、机器数 一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1. 比如...

    一. 机器数和真值

    在学习原码, 反码和补码之前, 需要先了解机器数和真值的概念.

    1、机器数

    一个数在计算机中的二进制表示形式,  叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.

    比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。

    那么,这里的 00000011 和 10000011 就是机器数。

    2、真值

    因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。

    例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

     

    二. 原码, 反码, 补码的基础概念和计算方法.

    在探求为何机器要使用补码之前, 让我们先了解原码, 反码和补码的概念.对于一个数, 计算机要使用一定的编码方式进行存储. 原码, 反码, 补码是机器存储一个具体数字的编码方式.

    1. 原码

    原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:

    [+1]原 = 0000 0001

    [-1]原 = 1000 0001

    第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:

    [1111 1111 , 0111 1111]

    [-127 , 127]

    原码是人脑最容易理解和计算的表示方式.

    2. 反码

    反码的表示方法是:

    正数的反码是其本身

    负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.

    [+1] = [00000001]原 = [00000001]反

    [-1] = [10000001]原 = [11111110]反

    可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算.

    3. 补码

    补码的表示方法是:

    正数的补码就是其本身

    负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)

    [+1] = [00000001]原 = [00000001]反 = [00000001]补

    [-1] = [10000001]原 = [11111110]反 = [11111111]补

    对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.

     

    三. 为何要使用原码, 反码和补码

    在开始深入学习前, 我的学习建议是先"死记硬背"上面的原码, 反码和补码的表示方式以及计算方法.

    现在我们知道了计算机可以有三种编码方式表示一个数. 对于正数因为三种编码方式的结果都相同:

    [+1] = [00000001]原 = [00000001]反 = [00000001]补

    所以不需要过多解释. 但是对于负数:

    [-1] = [10000001]原 = [11111110]反 = [11111111]补

    可见原码, 反码和补码是完全不同的. 既然原码才是被人脑直接识别并用于计算表示方式, 为何还会有反码和补码呢?

    首先, 因为人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的加减. (真值的概念在本文最开头). 但是对于计算机, 加减乘数已经是最基础的运算, 要设计的尽量简单. 计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了.

    于是人们开始探索 将符号位参与运算, 并且只保留加法的方法. 首先来看原码:

    计算十进制的表达式: 1-1=0

    1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2

    如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数.

    为了解决原码做减法的问题, 出现了反码:

    计算十进制的表达式: 1-1=0

    1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0

    发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在"0"这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0.

    于是补码的出现, 解决了0的符号以及两个编码的问题:

    1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原

    这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:

    (-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补

    -1-127的结果应该是-128, 在用补码运算的结果中, [1000 0000]补 就是-128. 但是注意因为实际上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示.(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的)

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

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

     

    四 原码, 反码, 补码 再深入

    计算机巧妙地把符号位参与运算, 并且将减法变成了加法, 背后蕴含了怎样的数学原理呢?

    将钟表想象成是一个1位的12进制数. 如果当前时间是6点, 我希望将时间设置成4点, 需要怎么做呢?我们可以:

    1. 往回拨2个小时: 6 - 2 = 4

    2. 往前拨10个小时: (6 + 10) mod 12 = 4

    3. 往前拨10+12=22个小时: (6+22) mod 12 =4

    2,3方法中的mod是指取模操作, 16 mod 12 =4 即用16除以12后的余数是4.

    所以钟表往回拨(减法)的结果可以用往前拨(加法)替代!

    现在的焦点就落在了如何用一个正数, 来替代一个负数. 上面的例子我们能感觉出来一些端倪, 发现一些规律. 但是数学是严谨的. 不能靠感觉.

    首先介绍一个数学中相关的概念: 同余

     

    同余的概念

    两个整数a,b,若它们除以整数m所得的余数相等,则称a,b对于模m同余

    记作 a ≡ b (mod m)

    读作 a 与 b 关于模 m 同余。

    举例说明:

    4 mod 12 = 4

    16 mod 12 = 4

    28 mod 12 = 4

    所以4, 16, 28关于模 12 同余.

     

    负数取模

    正数进行mod运算是很简单的. 但是负数呢?

    下面是关于mod运算的数学定义:

    clip_image001

    上面是截图, "取下界"符号找不到如何输入(word中粘贴过来后乱码). 下面是使用"L"和"J"替换上图的"取下界"符号:

    x mod y = x - y L x / y J

    上面公式的意思是:

    x mod y等于 x 减去 y 乘上 x与y的商的下界.

    以 -3 mod 2 举例:

    -3 mod 2

    = -3 - 2xL -3/2 J

    = -3 - 2xL-1.5J

    = -3 - 2x(-2)

    = -3 + 4 = 1

    所以:

    (-2) mod 12 = 12-2=10

    (-4) mod 12 = 12-4 = 8

    (-5) mod 12 = 12 - 5 = 7

     

    开始证明

    再回到时钟的问题上:

    回拨2小时 = 前拨10小时

    回拨4小时 = 前拨8小时

    回拨5小时= 前拨7小时

    注意, 这里发现的规律!

    结合上面学到的同余的概念.实际上:

    (-2) mod 12 = 10

    10 mod 12 = 10

    -2与10是同余的.

    (-4) mod 12 = 8

    8 mod 12 = 8

    -4与8是同余的.

    距离成功越来越近了. 要实现用正数替代负数, 只需要运用同余数的两个定理:

    反身性:

    a ≡ a (mod m)

    这个定理是很显而易见的.

    线性运算定理:

    如果a ≡ b (mod m),c ≡ d (mod m) 那么:

    (1)a ± c ≡ b ± d (mod m)

    (2)a * c ≡ b * d (mod m)

    如果想看这个定理的证明, 请看:http://baike.baidu.com/view/79282.htm

    所以:

    7 ≡ 7 (mod 12)

    (-2) ≡ 10 (mod 12)

    7 -2 ≡ 7 + 10 (mod 12)

    现在我们为一个负数, 找到了它的正数同余数. 但是并不是7-2 = 7+10, 而是 7 -2 ≡ 7 + 10 (mod 12) , 即计算结果的余数相等.

    接下来回到二进制的问题上, 看一下: 2-1=1的问题.

    2-1=2+(-1) = [0000 0010]原 + [1000 0001]原= [0000 0010]反 + [1111 1110]反

    先到这一步, -1的反码表示是1111 1110. 如果这里将[1111 1110]认为是原码, 则[1111 1110]原 = -126, 这里将符号位除去, 即认为是126.

    发现有如下规律:

    (-1) mod 127 = 126

    126 mod 127 = 126

    即:

    (-1) ≡ 126 (mod 127)

    2-1 ≡ 2+126 (mod 127)

    2-1 与 2+126的余数结果是相同的! 而这个余数, 正式我们的期望的计算结果: 2-1=1

    所以说一个数的反码, 实际上是这个数对于一个膜的同余数. 而这个膜并不是我们的二进制, 而是所能表示的最大值! 这就和钟表一样, 转了一圈后总能找到在可表示范围内的一个正确的数值!

    而2+126很显然相当于钟表转过了一轮, 而因为符号位是参与计算的, 正好和溢出的最高位形成正确的运算结果.

    既然反码可以将减法变成加法, 那么现在计算机使用的补码呢? 为什么在反码的基础上加1, 还能得到正确的结果?

    2-1=2+(-1) = [0000 0010]原 + [1000 0001]原 = [0000 0010]补 + [1111 1111]补

    如果把[1111 1111]当成原码, 去除符号位, 则:

    [0111 1111]原 = 127

    其实, 在反码的基础上+1, 只是相当于增加了膜的值:

    (-1) mod 128 = 127

    127 mod 128 = 127

    2-1 ≡ 2+127 (mod 128)

    此时, 表盘相当于每128个刻度转一轮. 所以用补码表示的运算结果最小值和最大值应该是[-128, 128].

    但是由于0的特殊情况, 没有办法表示128, 所以补码的取值范围是[-128, 127]

    展开全文
  • 本篇文章讲解了计算机的原码, 反码补码. 并且进行了深入探求了为何要使用反码补码, 以及...在学习原码, 反码补码之前, 需要先了解机器数和真值的概念. 1、机器数 一个数在计算机中的二进制表...
  • 原码反码补码的基础概念 为什么要使用原码反码补码 原码补码反码再深入 位运算运算说明 位运算简单应用 一、机器数和真值 机器数(computernumber)是数字在计算机中二进制表示形式 机器数...
  • 文章目录原码反码补码(适用于初学者)一、首先介绍概念二、具体情况1.下面看看这道例题2.正确解答 一、首先介绍概念 1.原码 原码就是符号位加上真值绝对值,即用第一位表示符号,其余位表示值。比如如果是8位...
  • 文章目录原码反码补码(适用于初学者)一、首先介绍概念二、具体情况1.下面看看这道例题2.正确解答 一、首先介绍概念 1.原码 原码就是符号位加上真值绝对值,即用第一位表示符号,其余位表示值。比如如果是8位...
  •  二、原码反码补码的基础概念  三、为什么要使用原码反码补码  四、原码补码反码再深入  五、数据溢出测试  六、位运算运算说明  七、位运算简单应用   一、机器数和真值  机器数...
  • 为了解释这个问题,我们先来了解下几个概念原码反码补码): 原码:它是一种计算机中对数字二进制定点表示方法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0...
  • 概念 原码:如果机器字长为n,那么一个... 补码补码反码的基础上按照正常的加法运算加1。 移码:移码不管正负数,将其补码的符号位取反。 总结:  正数的反码和补码都与原码相同。  负数的反码为对该数的...
  • #pragma mark 原码补码反码 ###pragma mark 概念 ###pragma mark 代码 #include <stdio.h> int main() { // 其实,数据存储在内存中都是存储二进制 // 二进制又可以分为 源码/反码补码 ...
  • c语言既具有高级语言特性,又具有低级语言功能,尤其是它提供指针运算和位运算,满足了编写系统软件需要,因而具有广泛用途和很强生命,也是C语言能够大部分取代汇编语言...一个数有原码反码补码三种
  • 补码原码反码的意义

    千次阅读 2017-03-21 22:29:59
    补码原码,反码计算机组成原理中,有补码原码反码的概念,但是一直搞不清楚为什么,只是记忆公式,不明白是怎么来的,现在写下来要如何理解各种码之间的关系,以及怎么来的。补码我们用C语言来举例。C语言中...
  • 本篇文章讲解了计算机的原码, 反码补码. 并且进行了深入探求了为何要使用反码补码, 以及更进一步...在学习原码, 反码补码之前, 需要先了解机器数和真值的概念. 1、机器数 一个数在计算机中的二进制表示形式
  • 原码反码补码

    2020-12-07 21:34:27
    力争让你对补码的概念不再局限于:负数的补码等于反码加一。 接触过计算机或电子信息相关课程的同学,应该都或多或少看过补码这哥仨。每次都是在课本的最前几页,来上这么一段:什么反码原码除符号位,按位取反。...
  • 最近在学习C语言,碰到了这些概念,花费了一下午时间,总结出了一些结论,仅供参考。 先说一些规定,也就是定义。 位 加法 有四种情况: 0+0=0 0+1=1 1+0=1 1+1=10(向高位进1,就是10进制,满10进1 一样运算) 0...
  • 力争让你对补码的概念不再局限于:负数的补码等于反码加一。 接触过计算机或电子信息相关课程的同学,应该都或多或少看过补码这哥仨。每次都是在课本的最前几页,来上这么一段:什么反码原码除符号位,按位取反。...
  • 在上学期学习c语言c++时候就接触到了原码反码补码这三个概念。 首先,我自己理解,原码反码补码这三个概念都是基于二进制而言。 原码包括符号位和数值位,数值位就是真值绝对值,符号位位“0”时...
  •  要了解数据在计算机中读取方式,首先我们要了解一个概念:机器字长。 机器“字”,是计算机能够一次性处理事务一个固定长度位组。一个“字”位数即字长。 机器字长是指:计算机进行一次整数运算所能处理...
  • 1. 基本概念  进制:是一种计数方式,数值表示形式  十进制:逢十进一 (如:13 == 1 * 10 + 3)  八进制:逢八进一 (如:15 == 1 * 8 + 5)  二进制:逢二进一 (如:1101 == 1 * 2 * 2 * 2 + 1 * 2 *...
  • 目录一、数据概述二、进制1、进制的概念2、计算机中为什么要用二进制3、八进制和十六进制出现是为什么4、进制间的相互转换问题三、数据的分类1、无符号整形(unsigned int)2、有符号整形(signed int)① 原码② ...
  • 记得之前学C语言的时候老师课上讲过一些,不过当时觉得考试不考,也就上课听了下,下课也没怎么多做了解。这次,Java课上再次提出来了,自己也超越了些资料,对这三种概念算是有所初步了解。 1、原码 数据储存一...
  • 基本概念进制:是一种计数方式,数值表示形式十进制:逢十进一 (如:13 == 1 * 10 + 3)八进制:逢八进一 (如:15 == 1 * 8 + 5)二进制:逢二进一 (如:1101 == 1 * 2 * 2 * 2 + 1 * 2 * 2 + 0 * 2+ 1)十六进制...
  • 补码的方法正数没有争议就是原码等于补码和反码为什么引入补码求负数反码的两种方法 正数没有争议就是原码等于补码和反码 为什么引入补码 数的原码表示百形式简单,适用于乘除运算,但用原码表示的数进行加减度法...
  • C语言时候,计算机二进制数以及有符号、无符号数的一些问题不是很清楚,刚才看到一个关于有/无符号数的...可是有关“补码的概念一说就得一节课,这一些我们需要在第6章中用一章的篇幅讲2进制的一切。再者,用
  • 负数的原码等于它本身,反码等于原码按位取反,补码等于反码+1,例如: 对于十进制数128,它的原码反码补码分别是 原码:1000 0000 反码:0111 1111 补码:1000 0000 2、数据在内存存放形式 需要明确知道,
  • 首先,关于原码补码反码的概念可以参考这个博客: http://blog.csdn.net/czg13548930186/article/details/72808385 想了解float数据在计算机中如何存储可以参考这篇博客: ...计算机存储的时候是以补码存数
  • C语言总结

    2020-03-11 10:58:53
    C语言总结1.C语言中的关键字1.基本类型 2.构造类型 3.指针类型 4.空类型基本类型构造类型空类型1.选择结构 2.循环结构 3.顺序结构选择结构循环结构声明变量的性质定义和声明...运算符算法的概念原码反码补码运算符优...

空空如也

空空如也

1 2 3
收藏数 48
精华内容 19
关键字:

c语言补码原码反码的概念

c语言 订阅