顺带说一个奇技淫巧
布尔代数
异
或
⊕
运
算
a
⊕
a
=
0
异或\oplus 运算 a\oplus a = 0
异或⊕运算a⊕a=0
a
⊕
0
=
a
a\oplus 0 = a
a⊕0=a
可以知道异或运算的每个逆元都是他本身,并且满足交换律和结合律,可以知道这是一个阿贝尔群…学过抽代的应该明白啥意思,我们知道异或运算有一个奇技淫巧来交换两个值
a
1
=
a
⊕
b
,
a_1 =a \oplus b,
a1=a⊕b,
b
1
=
a
1
⊕
b
,
b_1= a_1\oplus b,
b1=a1⊕b,
a
2
=
a
1
⊕
b
1
a_2=a_1 \oplus b_1
a2=a1⊕b1
下面来解释一下,其实只要把上面三个式子合在一起就可以了。
a
=
(
a
⊕
b
)
⊕
(
a
⊕
b
)
⊕
b
a = (a\oplus b)\oplus (a \oplus b)\oplus b
a=(a⊕b)⊕(a⊕b)⊕b
我们知道对于这个阿贝尔群来说逆元是本身,这样产生了单位元。
整数的表示方式原码,反码与补码
原码
假设电脑为8位字长,第一位0表示正,1表示负
1的表示
[0000 0001]
-1的表示
[1000 0001]
原码的问题
1 + -1 = [0000 0001] + [1000 0001] = -2
这显然不合理
反码
对于正数来说反码就是其本身
对于负数来说反码是符号位不变其余每一位取反
1的反码表示
[0000 0001]
-1的反码表示
[1111 1110]
1 + -1 = [1111 1111] 再取反 [1000 0000] 也就是-0
这样显然就会导致一个问题,也就是0我们有两种表示方法
同余
1
≡
11
m
o
d
10
,
意
思
是
说
1
和
11
除
10
的
余
数
一
样
都
是
1
1\equiv 11\mod 10 ,意思是说1和11除10的余数一样都是1
1≡11mod10,意思是说1和11除10的余数一样都是1
a
≡
b
m
o
d
c
⇒
(
a
+
c
)
≡
b
m
o
d
c
这
个
应
该
好
理
解
吧
a\equiv b\mod c \Rightarrow (a+c)\equiv b\mod c 这个应该好理解吧
a≡bmodc⇒(a+c)≡bmodc这个应该好理解吧
−
1
≡
9
m
o
d
10
,
对
于
负
数
来
说
只
要
加
上
c
让
它
变
正
数
就
可
以
了
-1\equiv 9\mod 10,对于负数来说只要加上c让它变正数就可以了
−1≡9mod10,对于负数来说只要加上c让它变正数就可以了
在看看取反码,假设为8位操作系统,对于符号位,我们相当于说对 2 8 2^8 28取同余,而数值大小位也就是前7位,我们相当于说对 2 7 2^7 27取余数
先看看正数
4 ≡ 2 7 + 4 m o d 2 7 , 4\equiv 2^7+4 \mod 2^7 , 4≡27+4mod27,
再看看负数
−
4
≡
2
7
−
4
m
o
d
2
7
,
-4\equiv 2^7-4 \mod 2^7 ,
−4≡27−4mod27,
这就是负数取反码的原理为啥符号位不变,其余位全部取反
那么为什么符号位不变呢?我认为这是有原因的
对于8位操作系统来说,我们能表示的
0
−
2
7
0-2^7
0−27已经拿来表示正数了,
而对于负数
0
到
−
2
7
0 到 -2^7
0到−27我们相当于说要加上
2
8
边
正
数
再
对
2
8
进
行
取
余
2^8边正数再对2^8进行取余
28边正数再对28进行取余
2
8
−
2
7
2^8 -2^7
28−27
对于正数来说也是如此,但正数也就会发生溢出
2
8
+
2
7
2^8 + 2^7
28+27
所以导致了符号位不变,而这也是我最开始所说的对于符号位,我们相当于对8位操作系统进行操作,而数值大小相当有7位
补码
对于正数来说,补码是其本身
对于负数来说,补码是其反码再加1
到补码这里就没有任何问题了,补码存在的意义是为了解决+0和-0的问题,我们在负数反码的基础上加1其实缩短了[1000,0001]相当于说缩短了负数的表示范围 从
−
2
7
—
—
−
0
变
为
−
2
7
—
—
−
1
加
上
一
位
后
让
多
的
那
个
溢
出
了
-2^7 ——-0 变为 -2^7 ——-1 加上一位后让多的那个溢出了
−27——−0变为−27——−1加上一位后让多的那个溢出了
最后你可以做一个小实验,体验下
#include<iostream>
using namespace std;
int main()
{
int a;
//这里a输入一个比较大的数比如1432443
cin>>a;
a = short(a);
//这里强制类型转换可能会出现负数,因为符合位的缘故
cout<<a<<endl;
return 0;
}
最后变成的时候做一个小总结:
int 类型不代表整数加法群,因为会有溢出现象;
double或者float也不能表示实数加法群,不仅仅有溢出,还有精度问题。