计算机中所有数据都是以二进制的形式储存的,运算直接对在内存中的二进制数据进行操作,因此处理数据的速度非常快。位操作只能用于整形数据,对float和double类型进行位操作会被编译器报错。
计算机底层保存的是补码,正数的原码等于补码
&:上下两位都是1是,结果为1
|:上下两位有一个是1,结果为1
当表示状态时,会用特定的数表示开关,比如文本四个状态:粗体(1)、斜体(2)、下划线(4)、中划线(8)转成二进制后按位或
粗体、斜体 = 0011 = 1 | 2
粗体、斜体、中划线 = 1011 = 1 | 2 | 8
~:按位取反:原来是0变1,原来是1变0;正数变成负的(绝对值+1),负数变成正的(绝对值-1)
- 原码:10进制变2进制,8位,并标明符号位。0正数,1负数,最左一位为最高位。
- 反码:按位取反
- 补码:除符号位不变,其他位取反
- 补码修复:最高位为正,末尾 -1 修复;最高位为负,末尾 +1 修复
- 转换:2进制变10进制
补充:为什么要有补码及补码修正?因为计算机中减法是通过加一个负数处理的,而负数又是通过补码保存的。目的就是为了统一加法减法
按位取反后为什么正数变成负的(绝对值+1),负数变成正的(绝对值-1),举例说明:
~9 结果:-10
原码:00001001
反码:11110110
补码:10001001
修正:10001010 1是负,加1修正
转换:-0008020 -> 10
~-9 结果:8
原码:10001001
反码:01110110
补码:00001001
修正:00001000 0是正,减1修正
转换:+0008000 -> 8
我还想知道计算机的补码修复原理为什么最高位为正,末尾 -1 修复;最高位为负,末尾 +1 修复
于是找到一篇博客《补码原理的个人理解》https://blog.csdn.net/jiaobuchong/article/details/83188674
取模运算和取余运算区别:
主要的区别在于对负整数进行除法运算时操作不同
对于整型数a,b来说,取模运算或者求余运算的方法都是:
1.求 整数商: c = a/b;
2.计算模或者余数: r = a - c*b.
求模运算和求余运算在第一步不同: 取余运算在取c的值时,向0 方向舍入(fix()函数);而取模运算在计算c的值时,向负无穷方向舍入(floor()函数)。
例如计算:-7 Mod 4
那么:a = -7;b = 4;
第一步:求整数商c,如进行求模运算c = -2(向负无穷方向舍入),求余c = -1(向0方向舍入);
第二步:计算模和余数的公式相同,但因c的值不同,求模时r = 1,求余时r = -3。
归纳:当a和b符号一致时,求模运算和求余运算所得的c的值一致,因此结果一致。
当符号不一致时,结果不一样。求模运算结果的符号和b一致,求余运算结果的符号和a一致。
另外各个环境下%运算符的含义不同,比如c/c++,java 为取余,而python则为取模
回到正题:补码计算方式
/ X 正数和 0 的补码,就是该数字本身
[X]补 = |
\ 模 -|X| 原码 X < 0 负数的补码,就是用模减去该数字绝对值的原码
在模一定的情况下,取模的结果就是我们想要的值。
计算机无法表示无穷大和无穷小的数字,无论何种数据类型都有一个上限和下限,超过了限定就会产生溢出。超出了上限就叫上溢出(overflow),超出了下限就叫下溢出(underflow)这不就是前面所讲的取模吗。所以计算机数值的溢出,就相当于取模,那我们前面所讲的同余的概念就可以在这个地方使用了。
很多教材会说负数的补码等于绝对值的原码取反加一,那这个又是怎么来的呢?
本文中说的补码的求法是:补码 = 模 - |x|(绝对值原码)
,比如要求 -7 的补码:
一个4位的二进制数能表示的数是有限的,从 0000 ~ 1111 ,0000表示0,1111表示 - 1,最大值7(0111),最小值-8(1000)
10000(模)- 0111
= 1111 + 1 - 0111
= 1111 - 0111 + 1 (加法交换率) // 1111 - 0111 这一步相当于取反
= 1000 + 1 // 于是可以得出 补码=绝对值的原码取反 + 1
所有的 x -y
都转换成 x + (-y)
,-y
用补码表示,直接将 x 的二进制和 -y
的补码二进制相加即可得到 x-y
的结果。
通过负数的补码将减法转换为加法,出现的进位就是模,舍去即可
4 - 2 = 2
0100
+ 1110
----------
10010
这里出现了进位,舍去进位。
结果 10010 超过模了,其实舍去就相当于 10010 - 10000(类似mod M)= 0010,
溢出就相当于取模,
我们最后得到的结果就是取模的结果。
模是 m,在模的基础上,-a 和 m - a 对于模 m 同余,m-a 是 -a 的补码。于是计算机中用 m-a 表示 -a,x - a = x + m - a (模是 m ),溢出就相当于是在取模。所以这也是我理解为什么使用补码的原因,其实就是数学里「同余」的概念,你会发现我们操作的其实就是在进行取模运算,这是一个很精妙的算法,它规避了在计算机中进行减法器的运算