原码、反码、补码之间的相互关系
1、10001的补码是取反后在再加1,也就是11110+1=11111;
2、如果是11111变回原码呢?我们可以采取逆过程先减1,11111-1=11110,再取反变为10001;
3、如果要是在补码变原码时先去反再加⼀呢?(就是问题中的说法)结果为11111先取反为10000,再加1,10000+1=10001。这个结果与2是⼀样的,并且也是和1中的原码相吻合。
在取反前减1和在取反后加1的效果是⼀样的。这就和-3-1=-(3+1)是⼀个道理。
计算机保存最原始的数字,也是没有正和负的数字,叫没符号数字
如果我们在内存分配4位(bit)去存放⽆符号数字,是下⾯这样⼦的
后来在⽣活中为了表⽰“⽋别⼈钱”这个概念,就从⽆符号数中,划分出了“正数”和“负数”
正如上帝⼀挥⼿,从混沌中划分了“⽩天”与“⿊夜”
为了表⽰正与负,⼈们发明了"原码",把⽣活应该有的正负概念,原原本本的表⽰出来
把左边第⼀位腾出位置,存放符号,正⽤0来表⽰,负⽤1来表⽰
但使⽤“原码”储存的⽅式,⽅便了看的⼈类,却苦了计算机
我们希望(+1)和(-1)相加是0,但计算机只能算出0001+1001=1010 (-2)
这不是我们想要的结果 (╯' - ')╯︵┻━┻
另外⼀个问题,这⾥有⼀个(+0)和(-0)
为了解决“正负相加等于0”的问题,在“原码”的基础上,⼈们发明了“反码”
“反码”表⽰⽅式是⽤来处理负数的,符号位置不变,其余位置相反
当“原码”变成“反码”时,完美的解决了“正负相加等于0”的问题
过去的(+1)和(-1)相加,变成了0001+1101=1111,刚好反码表⽰⽅式中,1111象征-0
⼈们总是进益求精,历史遗留下来的问题—— 有两个零存在,+0 和 -0
我们希望只有⼀个0,所以发明了"补码",同样是针对"负数"做处理的
"补码"的意思是,从原来"反码"的基础上,补充⼀个新的代码,(+1)
我们的⽬标是,没有蛀⽛(-0)
有得必有失,在补⼀位1的时候,要丢掉最⾼位
我们要处理"反码"中的"-0",当1111再补上⼀个1之后,变成了10000,丢掉最⾼位就是0000,刚好和左边正数的0,完美融合掉了
这样就解决了+0和-0同时存在的问题
另外"正负数相加等于0"的问题,同样得到满⾜
举例,3和(-3)相加,0011 + 1101 =10000,丢掉最⾼位,就是0000(0)
同样有失必有得,我们失去了(-0) , 收获了(-8)
以上就是"补码"的存在⽅式
结论:保存正负数,不断改进⽅案后,选择了最好的"补码"⽅案
⼆进制数在内存中以的形式存储。
取反:⼆进制每⼀位取反,0变1,1变0。
~9的计算步骤:
转⼆进制:0 1001
计算补码:0 1001
按位取反:1 0110
_____
转为:
按位取反:1 1001
末位加⼀:1 1010
符号位为1是负数,即-10
~-9的计算步骤:
转⼆进制:1 1001
计算补码:1 0111
按位取反:0 1000
_____
转为原码:
正数的补码和原码相同,仍为:0 1000,即8
原码表⽰法在数值前⾯增加了⼀位符号位(即最⾼位为符号位):正数该位为0,负数该位为1(0有两种表⽰:+0和-0),其余位表⽰数值的⼤⼩。例如,⽤8位⼆进制表⽰⼀个数,+11的原码为00001011,-11的原码就是10001011。
表⽰法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
补码表⽰法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。
(1)原码:在数值前直接加⼀符号位的表⽰法。
[+7]原= 0 0000111 B
[-7]原= 1 0000111 B
注意:
a. 数0的原码有两种形式:
[+0]原=0 0000000 B
[-0]原=1 0000000 B
b. 8位⼆进制原码的表⽰范围:-127~+127
(2)反码:
正数:正数的反码与原码相同。
负数:负数的反码,符号位为“1”,数值部分按位取反。
[+7]反= 0 0000111 B
[-7]反= 1 1111000 B
注意:
a. 数0的反码也有两种形式,即
[+0]反=0 0000000 B
[-0]反=1 1111111 B
b. 8位⼆进制反码的表⽰范围:-127~+127
(3)补码
正数:正数的补码和原码相同。
负数:负数的补码则是符号位为“1”。并且,这个“1”既是符号位,也是数值位。数值部分按位取反后再在末位(最低位)加1。也就是“反码+1”。
求负整数的补码,原码符号位不变,先将原码减去1,最后数值各位取反。(但由于2进制的特殊性,通常先使数值位各位取反,最后整个数加1。)
例如:符号位数值位
[+7]补= 0 0000111 B
[-7]补= 1 1111001 B
注意:
a. 采⽤补码后,可以⽅便地将减法运算转化成加法运算,运算过程得到简化。正数的补码即是它所表⽰的数的真值,⽽负数的补码的数值部份却不是它所表⽰的数的真值。采⽤补码进⾏运算,所得结果仍为补码。
b. 与原码、反码不同,数值0的补码只有⼀个,即 [0]补=00000000B。
c. 若字长为8位,则补码所表⽰的范围为-128~+127;进⾏补码运算时,应注意所得结果不应超过补码所能表⽰数的范围。
已知⼀个数的补码,求原码的操作其实就是对该补码再求补码:
⑴如果补码的符号位为“0”,表⽰是⼀个正数,其原码就是补码。
⑵如果补码的符号位为“1”,表⽰是⼀个负数,那么求给定的这个补码的补码就是要求的原码。
⼤多数语⾔都提供了按位运算符,恰当的使⽤按位运算符有时候会取得的很好的效果。
在我看来按位运算符应该有7个:
1、& 按位与
&是⼆元运算符,它以特定的⽅式的⽅式组合操作数中对应的位,如果对应的位都为1,那么结果就是1,如果任意⼀个位是0 则结果就是0。
1 & 3的结果为1
那我们来看看他是怎么运⾏的
1的⼆进制表⽰为 0 0 0 0 0 0 1
3的⼆进制表⽰为 0 0 0 0 0 1 1
根据 & 的规则得到的结果为 0 0 0 0 0 0 0 1,⼗进制表⽰就是1
2、| 按位或
|运算符跟&的区别在于如果对应的位中任⼀个操作数为1 那么结果就是1。
1的⼆进制表⽰为 0 0 0 0 0 0 1
3的⼆进制表⽰为 0 0 0 0 0 1 1
所以 1 | 3的结果为3
3、^ 按位异或
^运算符跟|类似,但有⼀点不同的是如果两个操作位都为1的话,结果产⽣0。
1的⼆进制表⽰为 0 0 0 0 0 0 1
3的⼆进制表⽰为 0 0 0 0 0 1 1
所以 1 ^ 3的结果为2
4、~
~运算符是对位求反,1变0,0变1,也就是求⼆进制的反码
1的⼆进制表⽰为 0 0 0 0 0 0 1
所以 ~1 的结果是-2
5、>> 右移
两个负数的补码相加>>运算符使指定值的⼆进制所有位都右移规定的次数,对于其移动规则只需记住符号位不变,左边补上符号位即按⼆进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),⾼位的空位补符号位,即正数补零,负数补1。
1的⼆进制表⽰为 0 0 0 0 0 0 1
所以 1>>1的结果为0
6、<< 左移
<<;运算符使指定值的⼆进制所有位都左移规定的次数,对于其移动规则只需记住丢弃最⾼位,0补最低位即按⼆进制形式把所有的数字向左移动对应的位数,⾼位移出(舍弃),低位的空位补零。
1的⼆进制表⽰为 0 0 0 0 0 0 1
所以 1<<1的结果为2 7、>>> ⽆符号右移
>>>运算符忽略了符号位扩展,0补最⾼位,但是只是对32位和64位的值有意义。位运算符在js中的妙⽤:
1、使⽤&运算符判断⼀个数的奇偶
偶数 & 1 = 0
奇数 & 1 = 1
那么0&1=0,1&1=1
2、使⽤~~,>>,<<,>>>,|来取整
~~3.14 = 3
3.14 >> 0 = 3
3.14 << 0 = 3 3.14 | 0 = 3 3.14 >>> 0 = 3(>>>不可对负数取整)
注意:~~-3.14 = -3 其它的⼀样
3、使⽤<<,>>来计算乘除
乘法:
1*2 = 2
1<>1 = 1(2/2的⼀次⽅)
4、利⽤^来完成⽐较两个数是否相等
1 ^ 1 = 0
1 ^ ⾮1数!=0
所以同⼀个数……同⼀个数等于0,否则不等于0
5、使⽤^来完成值交换
a = 1
b = 2
a ^= b
b ^= a
a ^= b
结果a=2,b=1
6、使⽤&,>>,|来完成rgb值和16进制颜⾊值之间的转换
16进制颜⾊值转RGB:
1function hexToRGB(hex){
2var hex = place("#","0x"),
3 r = hex >> 16,
4 g = hex >> 8 & 0xff,
5 b = hex & 0xff;
6return "rgb("+r+","+g+","+b+")";
7 }
RGB转16进制颜⾊值:
1function RGBToHex(rgb){
2var rgbArr = rgb.split(/[^\d]+/),
3 color = rgbArr[1]<<16 | rgbArr[2]<<8 | rgbArr[3];
4return "#"+String(16);
5 }
运⾏hexToRGB("#ffffff")返回"rgb(255,255,255)"
运⾏RGBToHex("rgb(255,255,255)")返回"#ffffff"
~ 运算符查看表达式的⼆进制表⽰形式的值,并执⾏位⾮运算。
Javascript 按位取反运算符 (~) ,对⼀个表达式执⾏位⾮(求⾮)运算。如 ~1 = -2; ~2 = -3;
js取反我只知道个!,但是~为什么也叫取反,他返回的⼜不是boolean类型?
~1,~2 的⼆进制⼜不是 -2 ,-3 ,怎么会转换成这么奇怪的值?
⽹友解答:
按位取反还真和boolean没多⼤关系,⼤体流程是这样的:
就来看看~1的计算步骤:
将1(这⾥叫:原码)转⼆进制= 00000001
按位取反= 11111110
发现符号位(即最⾼位)为1(表⽰负数),将除符号位之外的其他数字取反= 10000001
末位加1取其补码= 10000010
转换回⼗进制= -2
有⽹友对上⾯的答案进⾏了三点补充,如下:
按位取反的运算规则这么奇怪并不是JavaScript独有的,⽽是所有的计算机语⾔都是这样的。这样做的主要原因是为了为了统⼀减法和加法,在计算机中,减法会变成加⼀个负数,⽽负数会以补码的形式存储。⽽这样主要是因为补码和数字的⼗进制数有这么转换关系,负数:补码(x) = -x - 1,正数:补码(x) = x
因为补码是针对负数存在的,那么只要数据类型有⽆符号数,就没有这样的烦恼了,⽐如C语⾔有⽆符号整型,就能对⽆符号整型直接按位取反。
如果没有⽆符号类型,⽽且也只是想要按位取反,⽽不是附带补码的按位取反,需要另外的⽅法。让全1的数据和当前数据做按位抑或就⾏了。⽐如,你有⼀个32位的数据a,需要对它做按位取反,那么这样就⾏了:0xFFFF ^ a
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论