精华内容
下载资源
问答
  • 目录1 二进制2 原码反码补码3 位运算符4 位运算符使用技巧上回学习运算符时,漏了位运算符,因为位运算符理解起来稍微有点复杂,所以要单独写一篇~要理解按位运算符,要先了解计算机进行存储和计算的底层逻辑。...

    目录

    1 二进制

    2 原码、反码、补码

    3 位运算符

    4 位运算符使用技巧

    上回学习运算符时,漏了位运算符,因为位运算符理解起来稍微有点复杂,所以要单独写一篇~

    要理解按位运算符,要先了解计算机进行存储和计算的底层逻辑。

    因此我们从最基础的二进制说起。

    1 二进制

    只要学过计算机,就不可能不知道二进制。

    我们知道,十进制是逢十进一,譬如11,左边的1在十位上,代表10,右边的1在个位上,就是1。

    把1502这个数字拆开看,就是有1个1000,5个100,0个10,2个1,

    ,也就是说,十进制中的位数对应的就是10的幂,个位是0次幂,十位是1次幂,百位是2次幂,以此类推……

    同理,二进制中的位数对应的就是2的幂,那么对于二进制下的1010,转化成十进制下的数,就是

    用2进制数数,首先是0,然后是1,接下去是10,而不是2,因为二进制中只有0和1。

    小白可以练习一下从0写到10,写完对一下结果:

    e372737aa8356df89642b051c11955c8.png

    2 原码、反码、补码

    这三个码的产生,都和表示减法(负数)有关,他们的正数表示完全一样

    至于为什么为了表示个负数,出现了三个码,我们一个一个来说。

    2.1 原码

    日常生活中我们用负号(减号)解决了负数的表示问题,但在计算机中怎么加上这个负号呢?人们就想了个办法,用最高位存放符号,正数为0, 负数为1

    以4位二进值数为例,最高位是符号位,那么后面只有三位来表示数字。例如,0001表示1,要表示-1,就把最高位写成1,得到1001。

    当用8位来表示一个整数时,从右往左数的第8位即为符号位,当用16位来表示一个整数时,从右往左数的第16位即为符号位。我为了少写点数字>.<,本文举例都用4位。

    61008fc6dce1852fe3848c10dd063824.png

    这种方法简单直观,但在减法运算中有问题。计算1减去1,就是0001和1001加起来,会得到1010,这是咋了?1加-1,等于-2?

    因此原码无法进行减法运算。

    2.2 反码

    正数的反码和正数的原码完全一样,对负数原码的非符号位取反,就得到负数的反码(其实也就是将正数的反码统统取反),譬如+1的反码是0001,-1的反码就是1110。

    52150087bbc2c16dedadcd11b6945731.png

    此时我们计算+1和-1相加,即0001+1110=1111,正好是-0,相反数相加等于0,没有问题。

    但此时一个0有了两种表示法,0000和1111,一个数两种表示,有点奇怪。

    除此之外,虽然相反数相加没有问题,但是其他数的减法依旧不对劲,譬如0010+1110,等于10000,最高位1溢出,就是0000,所以2-1=0???

    所以,这个码还是不行。

    2.3 补码

    正数的补码和正数的原码完全一样,负数的补码等于负数的反码+1。但是,反码加1并不是补码的真正来历,只不过补码恰好等于反码加1,这么计算更加方便而已。

    9e2ff166324d6dd6830bc50048464beb.png

    关于补码的本质和定义,其实初看难以理解,但是仔细想想,会发现这就是自然而然、浑然天成的东西。

    我很喜欢一个词,“十方圆满”,一直以来我的微信签名都是这四个字。那么,这个词讲的是怎样一种状态呢?

    • 譬如,我们原地转个圈,就可以回到原点。
    • 譬如,我们在地球上,一直往东走可以到达的地方,一直往西走,也可以到达。
    • 譬如,我们把时钟的时针往前拨180度,和往后拨180度,得到的结果是一样的。
    • 再譬如,爱因斯坦说,如果人能看到无限远,那么他就能看到自己的后脑勺。

    我到底在说什么呢?

    对于四位二进制数,最大只能存放4位,就只有0000-1111这么大的空间,就只用$2^4=16$种排列组合的方式,空间是有限的。那么,这个空间圆不圆满呢?我们想办法让它从线性变成圆就好了,理解它,就像是理解24:00就是00:00,360°就是0°一样。

    先不管负数,假设我们有一条绳子,上面从左到右依次写着0、1、2…15、16,就像这样。

    38bf52b53a5a6652c71291a75aed1097.png

    我们把绳子首尾相连,也就是把写着0和16的两端拧到一起,圈成一个圆。

    5d09abfeb6c7a8fe22047db95a30b246.png

    这个圆上只有16个数字,16就等于0,这是为了方便后面和四位二进制数的16种排列组合相对应。

    我们从0出发,顺时针走1个单位,得到1,逆时针走1个单位,得到15,1+15=16。同样的,顺时针走7个单位得到7,逆时针走7个单位得到9,7+9=16。这个16有个专业的叫法,叫做

    这里的模是什么意思呢?简单举几个例子: - 24小时制下,24就是模。 - 转一圈360°,360就是模。 - 表上有12个刻度,12就是模。

    8f9784ba5506e8b86a3e4f5ba232dc63.png

    现在看这个圆,从0开始顺时针转,数值越来越大,最后到15,再转一个单位,就又回到0,没有什么问题吧?

    好,我们开始引入负数,并且把顺时针看成加法,把逆时针看成减法,这下会得到什么呢?

    顺时针走1个单位,认为是加1,所以得到1,圆的右边还是1~7。逆时针走1个单位,就是减1,得到-1,同理,把圆的左边都填满,得到下图。

    66a0d96f2406552c036b3d9aaf981e59.png
    • 首先,距离0相同距离的数,相加等于0,这解决了相反数相加为0的问题;
    • 其次,这个圆可以把减法转化成加法,a-b=c,其实等同于a+(16-b)=c,因为模是16。可以自己验证下,譬如1-2=-1(逆时针走2个单位),在这里就等价与1+14=-1(顺时针走14个单位)。

    完美啊!接下来,我们把这个圆上的十进制数字,替换成二进制就好了。

    3ce16dd334ae56e23db4d7e3cad9a4eb.png

    问题来了,正数的二进制码毫无疑问,负数的二进制码要怎么推出来呢?还有,1对面那个问号应该是什么数字?在7和-7之间,应该是8呢,还是-8呢?

    先不管那个问号是什么数,7的二进制码是0111,再加1,得到1000,问号处的二进制码应该是1000,再加1,就是10001,以此类推,我们就能补满整个圆上的码。

    582a61bcd468013903626a9394c0f624.png

    补完你会发现,-1本就该是1111啊!因为1111再加1,为10000,但因为四位,最高位的1溢出了,所以就得到0000,-1加1可不就是0吗!

    相应的,我们可以验证-4加4,即1100+0100,等于10000,溢出位不算,0000啊!这种表示法下,所有的相反数相加都是0000~

    再看看别的减法呢,譬如6-3,即0110+1101,等于10011,即0011,就是3~哈哈,都通过验证了呢!

    现在就剩最后一个问题了,就是0的对面应该是什么?从7出发,加1应该是8,但是从-7出发,减1应该是-8,这个1000到底代表哪个数?

    其实不难发现,圆的右边都是正数,最高位皆为0,左边都是负数,最高位皆为1,这有点像原码中人为定义的最高位是符号位,所以1000自然而然应该是-8。

    虽然求补码的过程中没有特意留出一个符号位,但最终得到的补码却可以用最高位来判断正负。补码的符号位就是这么来的。

    21a86fd01460d8e34fb668b4d8895c36.png

    比比赖赖这么多,其实求补码没那么麻烦,可以汇总成一句话:正数补码不变,求负数补码用模减去其绝对值即可。

    前面我们说过模是16,那么求a-b,其实等同于a+(16-b),所以求-b这个负数的补码,用16减b不就行了吗?比如说,求-2,就用16的二进制码减去2的二进制码。可是,四位二进制码的空间里,根本没有16这个数啊?没有就对了,因为它是模,也就是10000,在八位中16的表示是00010000。

    那么,我们计算-2的补码,其实就转化成: 10000 -0010 =1110

    2.4 小结

    总结一下:

    • 原码:将最高位作为符号位(0表示正,1表示负)。
    • 反码:如果是正数,则和原码一样;如果是负数,符号位为1,其余各位取反。
    • 补码:如果是正数,则和原码一样;如果是负数,将反码加上1。

    bf21a9984920c63f584ece8285105c20.png

    很多文章在解释补码时,都是原码→反码→补码这样的思路。

    先介绍最简单的原码,它方便人读数,但无法做减法,接着引申出反码,它是原码过渡补码的中间产物,但无法解决0的问题,最后引出补码,反码直接加1即可得到补码,这个码可以完美解决前面两个码的问题。但实际上我们也知道了补码的发展过程并不如此,之所以提供这样的思路,只是为了便于计算补码。

    关于补码的定义和本质,我解释得挺业余的,举的例子也不够严谨,主要是为了方便自己理解和记忆。要看专业的解释,就得去找权威书籍或教材来看了。

    3 位运算符

    计算机底层在存储数据的时候,都是用补码存储,位运算符就是基于补码进行的计算,包括:

    1. 位逻辑运算符: 与&,或|,异或^,取反~。
    2. 位移运算符:左移<< ,右移>> 。

    65b78cb3d832b5c47cfd293546a7e0bd.png
    a = 2
    b = 3
    print("a和b转换为二进制为:", bin(a), bin(b))
    -------------------------------------
    [output]: a和b转换为二进制为 0b10 0b11

    下面我就用2和3,也就是0010和0011举例。

    a = 0010  #2
    b = 0011  #3
    
    a&b = 0010  #2
    a|b = 0011  #3
    a^b = 0001  #1
    ~a = 1101  #-3
    
    a<<1 = 0100 #左移一位,相当于乘2,得到4
    a>>1 = 0001 #右移一位,相当于除以2,得到1
    a>>2 = 0000 #右移两位,相当于除以4,不能整除时向下取整,得到0

    4 位运算符使用技巧

    在日常工作中,用到位运算符的场景似乎不多,它能用来做什么呢?

    4.1 按位与

    通常,我们写程序判断奇偶数,是除以2看余数。现在可以用该数和1进行按位与,结果是1,就是奇数,是0,则为偶数。

    def Odd_Even(x):
        if x&1 == 1:
            print(x,'是奇数')
        else:
            print(x,'是偶数')
    
    Odd_Even(666)
    ---------------------
    [output]: '666 是偶数'

    4.2 按位或

    任意数和1按位或,可以向上求最接近的奇数。

    6|1
    ---------------------
    [output]: 7
    
    7|1
    ---------------------
    [output]: 7

    4.3 按位异或

    一个数a,另一个数b进行两次异或运算,最后结果不变,即(a ^ b) ^ b = a。

    5^7
    ---------------------
    [output]: 2
    
    5^7^7
    ---------------------
    [output]: 5

    因此用异或运算调换两个数字的值。

    a = 5
    b = 7
    a = a^b
    b = b^a
    a = a^b
    print(a,b)
    ---------------------
    [output]: 7 5

    当然Python中其实可以用一行代码就完成交换。

    a = 5
    b = 7
    a,b = b,a
    print(a,b)
    ---------------------
    [output]: 7 5

    简单的加密也可以用异或运算,比如实际密码是password,既怕忘了又怕直接写下来被别人看到,就可以用一个简单的key作为密钥,两者作异或运算,得到tip,把这个tip记到小本子里。忘记密码时,将key和tip做异或运算,就能得到原密码啦~

    password = 587645
    key = 111111
    tip = password ^ key
    print(tip)
    ---------------------
    [output]: 607610
    
    tip ^ key
    ---------------------
    [output]: 587645

    4.4 按位取反

    对一个数按位取反,等于它的相反数减1。

    ~55
    ---------------------
    [output]: -56

    对一个数两次取反,结果不变。

    ~~55
    ---------------------
    [output]: 55

    4.5 按位左移

    a左移b位,就是把a转为二进制后左移b位,后面缺位补0,相当于a乘以2的b次方,因为在二进制数后添一个0就相当于该数乘以2。

    5<<2
    ---------------------
    [output]: 20

    4.6 按位右移

    a右移b位,就是把a转为二进制后右移b位,前面缺位补0,相当于a除以2的b次方,并向下取整。

    14>>2
    ---------------------
    [output]: 3

    计算机中的数是用二进制来表示的,因此位运算可以更直接、更高效地实现运算操作。对于乘2除2,二进制左右位移一下就搞定,速度非常快,所以尽量用位移来代替代码中的乘除。

    最后注意一点,在Python中只能对整数进行位运算~

    参考链接:

    1)原码、反码、补码的产生、应用以及优缺点有哪些? - 张天行的回答 - 知乎

    2)原码,反码,补码的深入理解与原理

    3)Python位运算用途以及用法

    4)js 中位运算的应用

    5)位运算简介及实用技巧(一):基础篇

    展开全文
  • 故事是一个真实的故事,前两天要被一位小学弟折磨死,原码反码补码不懂就算了,讲了一遍还不懂。 我搞不懂是二进制太难还是我太难了呢?你们不信?立图为证: 他这问的给我直接问懵逼了,二进制符号位不参与...

    前言

    故事是一个真实的故事,前两天要被一位小学弟折磨死,原码、反码、补码不懂就算了,讲了一遍还不懂。在这里插入图片描述

    我搞不懂是二进制太难还是我太难了呢?你们不信?立图为证:
    在这里插入图片描述
    他这问的给我直接问懵逼了,二进制符号位不参与运算?我怎么听得给我都听糊涂了,哈哈哈,后来我就给他说了要参加运算,再后来又一个问题:
    在这里插入图片描述
    他这么确定的眼神给我搞得都有点懵逼,都吓得我打一段代码去验证一下结果没毛病,又巴拉巴拉给他讲了一通。

    我觉得应该可以了吧,结果在凌晨1.30的时候……
    在这里插入图片描述

    算了,算了,这孩子没得救了,不管了。给女票滴滴打算晚安,但我也曾想起自己在原码、反码、补码上的困惑。

    • 记得刚学c++的时候:这啥玩意代码不要求,不学
    • 刚学操作系统、组成原理的时候:emumm,跳过跳过。

    所以以前的我也一直没能搞懂二进制,并且很排斥二进制:既然把方法数字都封装好为啥还要这么麻烦的搞二进制。但事实上二进制这个知识是无论如何也避免不了的知识点。想着要拯救更多苦于二进制或者说原码反码补码的小学弟小学妹们,我得站出来做点什么。

    就先拿女朋友做小白鼠试验一下。网友直呼内行!
    在这里插入图片描述
    以下均为小白鼠内容为了确保实验结果呃严谨性对话情景就不给大家带入了。

    二进制数字

    什么是二进制?百度百科对二进制是这么定义的:

    二进制(binary)在数学和数字电路中指以2为基数的记数系统,以2为基数代表系统是二进位制的。这一系统中,通常用两个不同的符号0(代表零)和1(代表一)来表示 [1] 。数字电子电路中,逻辑门的实现直接应用了二进制,因此现代的计算机和依赖计算机的设备里都用到二进制。每个数字称为一个比特(Bit,Binary digit的缩写)

    其实二进制的01就是对应数字电路中的关开,所以在整个计算机中所有的东西都是二进制科学,但我们只需要研究数字类型的二进制的关系这个也是最简单的,因为二进制本身就能代表数字。

    如果说不谈啥原码、反码、补码,光光看二进制跟十进制的关系,也不考虑位数,我想大部分人可以搞得懂。

    • 比如2的二进制:10,3的二进制:11,4的二进制:100,5的二进制:101.
    • 负数的二进制怎么搞?-2二进制-10?-3二进制-11?这样不太妥吧,怎么跟着这么一个负数?(问题一)

    另外,这种不确定长度的二进制如果是一个数组我该怎么在计算机内存中找的到 (问题二)
    以一个可能不太恰当的图展示一下:
    在这里插入图片描述
    大家一看直呼这样不行,所以在计算机数值类型设计之初就明确表示:计算机基本数据是定长的,并且有两部分组成:符号位(一位)和数值位(若干位),其中符号位的0或者1分别表示正和负数,而数值位就是表示数据的大小。

    你可能直呼:到底多少位表示一个数字呢?如果太长位数据如果很小(前面都是0)就会造成浪费,造成内存浪费,而位数太短又会导致装不下,网友们直呼真难。

    伟大的设计者们当然考虑了这个问题,他们将数值二进制的长度分为不同长度供你使用,在java中有这8种基本数据类型(1byte=8bit):

    基本类型 长度(byte) 包装类型 取值范围
    byte 1 Byte -128~127
    short 2 Short -32768 ~ 32767
    int 4 Integer -2147483648~2147483647
    long 8 Long -9223372036854774808~9223372036854774807
    float 4 Float 3.402823e+38~1.401298e-45(e+38 表示乘以10的38次方,而e-45 表示乘以10的负45次方)
    double 8 Double 1.797693e+308~4.9000000e-324
    char 2 Character
    boolean 官方未确定 Boolean true false

    比如说你byte a=1,他在内存中就是这样的:

    0000 0001

    如果你 int b=1;因为int是32位,那么他在内存中是这样存的:

    00000000 00000000 00000000 00000001

    你可能会问为啥没讲负数?别急慢慢来,下面原码、反码、补码讲着呢。另外需要注意的是,二进制进行加法如果溢出,溢出部分不会记录,只会保存有效部分,所以选用什么数据类型也要掂量目标数据的大小范围。

    原码

    上面既然初步知道了二进制数字的一些规律,那么就让它来的更猛烈一些吧。原码是什么意思呢?

    • 原码就是二进制的初始表示符号位,即最高位为符号位:正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。

    在这里插入图片描述
    是不是很直接明了的展示一个值?原码的优势就是比较明显的表示一个值。能够清楚的知道这个二进制数表示是多少,简单直观

    但我们是否就可以使用原码畅通无阻了呢?

    当然不可以,原码虽然可以很容易的表示一个正负数,但是我们观察它的加法:

    在这里插入图片描述

    正数相加没问题,但是负数的加法就出问题了:负数的加法只考虑绝对值数值的增加而未考虑负数的特性。而负数加负数的绝对值相反,所以在原码上负数的加法就成了一个难题,走不通。

    反码

    负数的原码无法实现加法,因为原码如果进行加法实现的是与符号无关数值绝对值的加法。所以这点和负数的加法规则矛盾,并且计算机也只会加法。咱们只能另从它计。

    此时,有些伟大的大佬就发现了反码这个东西,而反码的定义是这样的:正数的反码与其原码相同;负数的反码是对正数逐位取反,符号位保持为1. 因为负数原码的加法是相反的(即加一变成减一的操作),我们想着如果给负数原码中的数字01颠倒那么这个数字就会有比较有趣的事情。

    • 原码中本来比较大的数字(-1,-2等)在这样转换后看起来变得很小。原本很小的数字经过这样的转换后看起来很大。(也就无法直观一下看出这个数字是多少)
      在这里插入图片描述

    • 转换后的数字进行加法(正数)运算,在进行01互换之后可以进行正常加法的逻辑
      在这里插入图片描述

    • 负数相加好像看起来也没问题。

    但是真的就可以了嘛?正数负数用反码表示可以畅通无阻了?no no no。咱们记得原码中有+0,-0.但是不影响操作吧。看看反码中+0,-0的情况:
    在这里插入图片描述

    你看看,反码它也不行啊,what should I do?看下面的补码分析。

    补码

    反码为啥会出现这个问题呢?主要是正负0占了两个坑:
    在这里插入图片描述
    也就是如果你用反码表示这个数,用它进行加法运算,正数范围内玩没问题,负数范围内玩也没问题,但是当你从负数迈到正数的时候会经过两个0(-0,+0)两个零重复表示了。

    这该如何表示呢?我们看看这些数字反码的规律:

    -3的反码: 1111 1100
    -2的反码: 1111 1101
    -1的反码: 1111 1110
    -0的反码: 1111 1111

    +0的反码:0000 0000

    这些负数的反码,如果都能加个1,那么这样正负0的矛盾不久不存在了嘛?!!这就是所谓的补码:符号位不变,正数的补码为和原码、反码一致,负数的补码为其反码加1.

    在这里插入图片描述

    这样我们就解决了所有难题,叱咤风云的进行计算了,其实我们在计算机中二进制也是用补码表示所有数值。

    对于补码,你确实无法直接看出它是多少,负数或许理解起来可能还有那么一点点抽象,我们该如何理解补码呢?
    我是这么理解的:二进制数把数据分为正负两个部分,分别表示两个区间:

    在这里插入图片描述
    什么意思呢?这个也就是说你可以把负数看成一部分,正数看成一部分。而每个部分的数值也是相同的:无论负数还是正数出去符号位,都是从 000 0000~111 1111(byte为例)分布。如果前面符号位为1就是表示负数,负数的最小到最大(-128 ~ -1)共128个,如果是0就是正数的最小和最大(0 ~ 127)共128个。这样理解是不是容易很多呢!

    测试

    上面讲了那么多道理,咱们测试一下吧,用以下代码验证上述结果

    //微信公众号:bigsai
    public class Main {
    	public static void main(String[] args) {
    		int a =-1;//11111111 11111111 11111111 11111111
    		int b=1;  //00000000 00000000 00000000 00000001
    		System.out.println(Integer.toBinaryString(a));//输出-1的二进制
    		System.out.println(Integer.toBinaryString(b));//前面的0会省略
    		
    		/*
    		 * 127 + 1:
    		 *  0111 1111
    		 * +0000 0001
    		 * =1000 0000 = -128
    		 */
    		byte c=127;
    		byte d=(byte)(c+1);
    		System.out.println(d);
    		
    		/*
    		 *  -1+1
    		 *   1111 1111
    		 * + 0000 0001
    		 * =10000 0000(理论上) = 0000 0000(只有8位有效位) =0
    		 */
    		byte e=-1;
    		byte f=(byte)(e+1);
    		System.out.println(f);
    	}
    }
    
    

    输出结果:
    在这里插入图片描述
    这段代码意会巩固以下就好了。

    总结

    到此,是不是对原码、反码、补码理解更透彻一点了呢?不管你懂没懂,反正问她懂了吗她是这么说的:

    在这里插入图片描述

    总结一下:

    • 原码,能够直接的显示数值的大小状况。结构为符号位+数值部分。符号位0代表正,1代表负。
    • 反码,是一个过渡码,其实就是在求补码或者原码补码转换过程中需要用到。其规则是正数反码等于原码,负数反码符号位不变,数值位0变成1,1变成0.
    • 补码,计算机中数值都是以补码的形式进行计算的,它有效的解决负数加法问题,也可以使符号位直接参与运算。并且原码、反码、补码转换很简单。

    好了,本片已经结束了,讲完自己的气也消了一半,希望上面那个学弟能看到这篇文章然后点个赞。

    如果感觉不错,欢迎关注公众号:bigsai 一个和你一起成长的小哥哥。如果有错误或者不太好的地方,欢迎指正!(笔者最近开展力扣打卡计划,关注回复进群一起刷题)
    在这里插入图片描述

    展开全文
  • 原码反码补码傻傻分不清?计算机最底层存储为什么要用补码?补码怎么来的?补码怎么算的?为什么八位二进制能表示-128-127?总结了一些知识,希望能对你有所帮助

    一、原码

    原码定义

      原码(true form)是一种计算机中对数字的二进制定点表示方法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小.
    比如我们用8位二进制表示一个数(以下例子均默认为八位二进制)

    原码
    127 01111111
    +0 00000000
    -0 10000000
    -127 11111111

    由上表可知8位二进制的原码表达的范围是 -127-----127

    原码的优点

      简单直观,便于输入输出

    原码的缺点

      当有负数参与加减运算时,计算会变得复杂最直观的如 00000001(1)+10000001(-1)=10000010(-2)显然不正确。所以符号位需要和数值位分开运算,这样明显增大了硬件的消耗。
    为此引入了另一种数的表示方式 补码

    反码

    反码是原码求补码的格过度。(个人理解)

    原码求反码

    正数的反码是其本身
    负数的反码将其原码除符号位外的所有位取反(0变1,1变0)
      例-9的原码是00001001,反码是11110110

    补码

    反码求补码

    正数的补码与原码,反码相同 。
      例:+9的原码,反码,补码都是00001001。
    负数的补码:将与之对应的反码加1 。
      例:-9的原码是10001001,反码是11110110,补码是11110111

    原码 反码 补码
    127 01111111 01111111 01111111
    1 00000001 00000001 00000001
    +0 00000000 00000000 00000000
    -0 10000000 1111 1111 00000000
    -1 10000001 11111110 11111111
    -127 1111111 10000000 10000001
    -128 10000000

    从上表中可以发现,0的补码是唯一的,而且补码可以多表示一个数(-128),这也就是计算机中一字节(8比特)为什么可以表示-128——127的理由了。

    补码的运算规则

    通过将原码转为补码,可以发现补码间能直接相加或相减
      补码的加法规则是:[X + Y]补 = [X]补 + [Y]补
      补码的减法规则是:[X - Y]补 = [X]补 + [-Y]补
      对于加后有溢出的情况,舍去最高位即可
      例: 如-1加-127得到的是110000000,是九位二进制,舍去最开始的1,得到的即是-128的补码。

    为什么补码能解决负数加减法问题,以及负数求补码的另一种思路

      原码之所以不方便加减法是因为当有负数参与运算时,符号位不统一导致结果不正确的问题。其实简而言之,就是一对相反数相加不为0,如在原码中(-1)+(1)的结果为(-2)
      而已知在原码中正数之间是满之间足加减法的直接运算,因此只需要保留正数的表达方式,改变负数的表示方式,就能让正负数都满足加减法运算。说白了,就是让(1)+(-1)=0。当然首先我们要规定0的表示方式只能是00000000,不然负数的表示方式就会不唯一。咱们将这种数的二进制表达方式称为补码。
      已知(1)的补码保留了原码的表达方式是00000001,可以很简单得推出(-1)的补码是11111111(即0-1)。且(2)得补码是00000010,可推出(-2)的补码是111111110。以此类推。由此种方式得出的补码自然而然可以解决正负数之间的加减问题。
       因此我们不难推出负数补码的另一种计算方式。即九位二进制的0(000000000)减去该负数的相反数的原码。

    展开全文
  • 本文为大家解析了java原码补码反码的关系,供大家参考,具体内容如下原码:不管源数据是十进制还是十六进制,统统将数字转成二进制形式反码:把原码的二进制统统反过来,0变成1,1变成0补码:负数的反码加1,就是...

    5f21b83631127c88fef2639d476b9cf3.png

    本文为大家解析了java原码补码反码的关系,供大家参考,具体内容如下

    原码:不管源数据是十进制还是十六进制,统统将数字转成二进制形式

    反码:把原码的二进制统统反过来,0变成1,1变成0

    补码:负数的反码加1,就是负数的补码

    例子1:

    十进制整数 -5,-5的原码101,-5的反码1,010,-5的补码1,011,

    所以,-5的反码是-2,-5的补码是-3,其中前面的"1,",表示正数负数

    例子2:

    十六进制  -ff9B

    原码  11111111111110011011

    反码  00000000000001100100    十进制100

    补码  00000000000001100100   十进制101

    原来正确的操作流程是,把16进制ff9B转成2进制,然后直接反码,再算补码,就是温度数据

    代码验证:

    package comtest.example.admin.znum;

    /**

    * Created by wrs on 2019/6/5,16:25

    * projectName: Testz

    * packageName: comtest.example.admin.znum

    * 输入一个真值(整数)求它的原码,反码,补码

    */

    import java.util.Scanner;

    public class Test {

    public static void main(String[] args) {

    System.out.println("True value--> original code");

    System.out.println("Please enter an integer!!!!!");

    Scanner sc = new Scanner(System.in);

    int value = sc.nextInt();

    StringBuilder syuan = new StringBuilder();

    if (value > 0) {

    String Bvalue = Integer.toBinaryString(value);//将一个整数转换成字符串类型的二进制数

    int n = Bvalue.length(); //二进制的数字的个数n

    syuan.append("0,");

    syuan.append(Bvalue);

    System.out.println("Original code " + syuan); //原码

    System.out.println("Complement code " + syuan); //补码

    System.out.println("Inverse code " + syuan); //反码

    // System.out.println("二进制数的n "+n);

    } else if (value < 0) {

    int value2 = Math.abs(value); //负数的绝对值

    int value3 = value2 - 1; //减一求反,求补码

    String Bvalue = Integer.toBinaryString(value2);

    String BFvalue = Integer.toBinaryString(~value2);

    int n = Bvalue.length();

    String str = BFvalue.substring(BFvalue.length() - n); //截取反码的后几个数

    syuan.append("1,");

    syuan.append(Bvalue);

    System.out.println("Original code is :" + syuan);

    System.out.println("Inverse code is :1," + str);

    String BBvalue = Integer.toBinaryString(~value3);

    String str3 = BBvalue.substring(BFvalue.length() - n);

    System.out.println("Complement code is :1," + str3);

    } else {

    System.out.println("0 Original code is not only");

    System.out.println("[+0]riginal code 00.....0");

    System.out.println("[-0]riginal code 10.....0");

    System.out.println("--------------------------------------------");

    System.out.println("0 Complement code is not only");

    System.out.println("[+0]和[-0] Complement code 00.....0");

    System.out.println("---------------------------------------------");

    System.out.println("0 Inverse code is not only");

    System.out.println("[+0]Inverse code00..........0");

    System.out.println("[-0]Inverse code11..........1");

    }

    System.out.println("-------------------------------------------------");

    }

    }

    运行效果:

    -------------------------------------------------

    True value--> original code

    Please enter an integer!!!!!

    -65435

    Original code is :1,1111111110011011

    Inverse code is :1,0000000001100100

    Complement code is :1,0000000001100101

    -------------------------------------------------

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持云海天教程。

    展开全文
  • 为什么要有原码反码补码不同的编码数值在计算机中表示形式为机器数,计算机只能识别0和1,使用的是二进制,而在日常生活中人们使用的是十进制,"正如亚里士多德早就指出的那样,今天十进制的广泛采用,只不过我们绝大...
  • 本篇文章讲解了计算机的原码反码补码,并且进行了深入探求了为何要使用反码补码,以及更进一步的论证了为何可以用反码补码的加法去计算原码的减法。论证部分如有不对的地方请各位牛人帮忙指正!希望本文对...
  • 计算机内部采用二进制表示数值。如十进制数10用二进制数表示为1010。...最高位表示符号,0为正,1为负 来看看用原码表示的数在进行加减乘除运算是会有什么问题: 十进制:1-1=1+(-1)=0 原码:(0000 0001)-(0000...
  • 声明:笔者仍为在校学生,有错误...(以八位二进制为例)整数的各种码表示:(以+ - 35为例)原码:(+35)00100011,就是35的二进制数,注意始终要8位,前面补零;(-35)10100011,最高位放符号位,1表示负。补码...
  • 原码-反码-补码

    2012-06-19 22:33:55
    十进制 → 二进制 (怎么算?要是不知道看计算机基础的书去)47 → 101111有符号的整数 原码 反码 补码 47 00101111 00101111 00101111(正数补码原码反码相同,不能从字面理解) -47 10101111 ...
  • 1.原码反码补码定义1.原码将最高位作为符号位(以0代表正,1代表负),其余各位代表数值本身的绝对值(以二进制表示)。为了简单起见,我们用1个字节来表示一个整数。+7的原码为: 00000111-7的原码为: 100001112....
  • 学习计算机组成原理的时候学过这个,结果今天看了一道LeetCode的习题,发现自己补码怎么算的都给忘了,罪过罪过,于是乎就搜了相关资料回忆了下,以下这篇文章写得很好,想记录下来方便以后查看。 ...
  • 计算机组成(运算器、控制器、存储器、原码反码补码)1、运算器算术逻辑单元(ALU)、累加器、状态寄存器、通用寄存器组等组成。算术逻辑运算单元(ALU)的基本功能为加、减、乘、除四则运算,与、或、非、异或...
  • 计算机要存储数据,必须使用二进制,那么我们要怎么存储二进制呢? 有的人会说这不是废话,直接将十进制转换成二进制不就好了? 是的,直接转成二进制是可以使用的,所以直接转成二进制这种办法我们称之为原码。 ...
  • 补码(Two‘s complement)、反码(Ones‘ Complement)、原码(Sign Magnitude):注意,补码反码中,撇号的位置不同。术语补码来源于这样一个情况,对于非负数x,我们用2? - x(这里只有一个2)来计算-x的n位表示;术语...
  • 这个问题不是存储问题,而是程序设计人员的解释问题,类似这样的问题在后边的存储设备中也存在( 关注下一篇)百科概念计算机中的符号数有三种表示方法,即原码反码补码。三种表示方法均有符号位和数值位两部分,...
  • 今天早上看java的源代码,发现: 用计算器转成十进制后是下面这个值: 然后我就纳闷了,Integer的最小值,不可能怎么大吧?...正数:原码=反码=补码 负数:原码=补码取反(符号位以为的数...
  • 关于按位取反怎么算

    千次阅读 2020-09-21 17:43:18
    三、按位取反怎么算 按位取反:二进制的每一位都取反(符号位+数据位) 公式法: ~x=-(x+1) 举两个例子:~11=-(11+1)=-12 ~(-11)=10 公式法的内部是如何计算的呢: 以~11为例: ~11的计算步骤: 计算11的补码 转二...
  • 正数:原码=反码=补码 负数:反码=原码的所有位(符号位除外)取反 补码=反码+1 所以一个字节: 最大正数二进制是0111 1111 = 64+32+16+8+4+2+1=127 最小负数二进制是1000 0000→ 1111 1111(反码)→ +1...
  • 负数的补码等于反码+1,反码就是原码取反。 为了方便注意符号位。 看个例子~6=-7 首先这个是正6取反运算的值是多少。 首先6的二进制原码为 110,一般这样写,带上符号位00110,最高位为符号位0,表示正数。 ...
  • Java语言概述

    2020-10-02 14:07:01
    十六进制2.7不同进制数据的表现形式2.8任意进制到十进制的转换图解2.9十进制到其他进制的转换2.10原码反码补码2.11变量的概述及格式2.12数据类型的概述和分类2.13定义不同数据类型的变量2.14使用变量注意事项2.15...
  • 二进制运算

    2021-01-05 09:57:34
    二进制有原码 反码补码 计算机中在运算时使用的都是补码 btye 类型 (-128)- (127) btye类型在java中站一个字节 一个字节=8位(bit) 计算机只能存储0和1 1111 1111 当全部存满时出来是255 如果只是这样的话...
  • baidu来的说法是酱紫的 ...经过半天的折磨,终于搞清楚怎么算了,但是发现这样真心麻烦,0101写的比较累,经过观察,貌似可以这样做: 即:假设A为原来的整数,则~A = -|A + 1| 请教这么做是否正确
  • (2)反码补码运算 (3)计算机以补码的方式存储(算原码),后面的常见编码了解一下 二、逻辑代数 (1)与或非、异或、同或器件真值表(怎么画) (2)常用公式,反演定理 (3)逻辑函数的描述方法及其相关转化 (4)最小项之和,...
  • 二进制的乘除

    千次阅读 2019-04-17 09:16:04
    当然也是因为一直有一个东西困扰我,就是学到二进制时,当时只教了二进制的加减,(什么原码反码补码的的东西(小声bb))但是没有教二进制的乘除。在加上老师告诉我们计算机只能进行二进制的加法,所以我就在...
  • 怎么算 假设M和N都是n位的有符号二进制数,则M-N等于M+N的补码 M−N=M+(2n−N) M-N=M+(2^n-N) M−N=M+(2n−N) 为什么可以这么算 首先,在计算机系统中取负数有三种方法 补码(Signed-2-Complement):取反加一 反码...
  • 疯狂的程序员

    热门讨论 2012-07-18 18:05:32
    ”其实在学校外头用激光打印,每张A4是3毛钱,到那家公司,就是6块钱,不过因为他是代理,就给他4块钱。这时他才知道,有时候生意就是亏着本也得做。一个月下来,绝影陪了15块钱。土匪他们卖掉100多根笔芯。绝影...

空空如也

空空如也

1 2
收藏数 26
精华内容 10
关键字:

原码反码补码怎么算