二进制运算理解及在代码中的运用

一讲计算机的发展,必定会提到二进制。虽然二进制对计算机的重要性经常被强调,但在利用高级语言(如:C#)的开发中,用得还是相对较少的。可这相对较少的运用,并不能成为我们不去理解他的借口。

一、二进制的运算。

(一)算术运算

从我们日常中熟悉的十进制来理解。从十进制的“0,1,2,3,4,5,6,7,8,9”减少到“0,1”。每位的容量从10到2的变化,仅此而已,就是这么简单。

 

1.加法:0+0=0,0+1=1 ,1+0=1, 1+1=10(向高位进位)

 

2.减法:0-0=0,0-1=1(向高位借位) 1-0=1,1-1=0

 

3.乘法:0*0=0,0*1=0,1*0=0,1*1=1 

 

4.除法:0÷0=0,0÷1=0,1÷0=0 (和十进制相同,不能被0除,无意义),1÷1=1

 

说起这个,给大家讲个冷笑话。今天中午下楼时,电梯已经到1楼了,我却还愣在那儿。你们猜为什么?因为我还在等0楼。

这是一个程序员才能明白的笑话。

 

(二)逻辑运算

将1理解为布尔值true,将0理解为布尔值false。

 

1.加法:通常用符号“+”或“∨”来表示(或运算)

一个为真,结果即为真。

0+0=0, 0∨0=0

0+1=1, 0∨1=1

1+0=1, 1∨0=1

1+1=1, 1∨1=1

 

2.乘法:通常用符号“×”或“∧”或“·”来表示(与运算)

都为真时,结果才为真。
0×0=0, 0∧0=0, 0·0=0
0×1=0, 0∧1=0, 0·1=0
1×0=0, 1∧0=0, 1·0=0
1×1=1, 1∧1=1, 1·1=1
 
3.否定:(非运算)
原本为真,结果为假,原来为假,结果为真。
0=1 非0即1
1=0 非1即0
 
4.异或:通常用符号"⊕"表示(半加运算)
只有一个为真,一个为假时,结果才为真。
0⊕0=0 0同0异或,结果为0
0⊕1=1 0同1异或,结果为1
1⊕0=1 1同0异或,结果为1
1⊕1=0 1同1异或,结果为0
 
(三)位运算
理解逻辑运算后,再来看位运算就容易多了。简单地说,位运算就是对二进制的对应位进行逻辑运算。
以十进制5转换为二进制为101,十进制19转换为二进制为10011为例。
 
1.按位或:通常用符号"|"或"or"表示
101|10011=00101|10011
各位对应按逻辑或运算,有一方为1即为1。
最后结果为:10111。
 
2.按位与:通常用符号"&"或"and"表示
00101&10011
各位按逻辑与运算,两方为1结果才为1
最后结果为:1
 
3.按位异或:通常用符号"^"或"xor"表示
00101^10011
各位按逻辑异或运算,一方为0另一方为1结果才为1
最后结果为:10110
 
4.按位取反:通常用符号"~"或"not"表示
将本身各位,0换为1,1换为0。
以一个字节(八位)为例:
~0000 0101=1111 1010
~0001 0011=1110 1100
 
5.按位左移:通常用符号"<<"或"shl"表示
将本身各位向左移动相应位数。
0000 0101<<1=0000 1010
0001 0011<<1=0010 0110
 
6.按位右移:通常用符号">>"或"shr"表示
0000 0101>>1=0000 0010
0001 0011>>1=0000 1001
 
二、应用实例
我们以贴有Flags标签的枚举值举例说明,二进制的一点用法。
首先,创建一个枚举类。
    [Flags]
    public enum PFive
    {
        Russia = 1 << 0,
        China = 1 << 1,
        USA = 1 << 2,
        UK = 1 << 3,
        France = 1 << 4
    }

这里,我们在用枚举项赋值时使用了按位左移运算。经过上面的介绍,我们很容易算出:

Russia = 1 << 0=1  (二进制1)
China = 1 << 1=2   (二进制10)
USA = 1 << 2=4   (二进制100)
UK = 1 << 3=8     (二进制1000)
France = 1 << 4=16   (二进制10000)

把1按二进制的位,一步一步往左移,是不是非常直观。

我们再来创建一个方法来判断常任理事国中,哪些国家是英语国家。

        public static string CanSpeakEnglish(PFive p5)
        {
            if (((PFive.USA | PFive.UK) & p5) == p5)
            {
                return p5.ToString() + " is a English Country.";
            }
            else
            {
                return p5.ToString() + " is not a English Country.";
            }
        }

这里我们重点要提的是这一句代码:

((PFive.USA | PFive.UK) & p5) == p5

我们知道美国和英国是英语国家,那只要传入的国家是这两个国家中的一个,那它也就是英语国家了。
PFive.USA=4=100;
PFive.UK=8=1000;
PFive.USA | PFive.UK=100|1000=1100;

现在假设传入的国家是中国

PFive.China=2=10;

(PFive.USA | PFive.UK) &PFive.China=1100|0010=0000
0000!=PFive.China,返回false

现在假设传入的国家是英国

PFive.UK=8=1000;
(PFive.USA | PFive.UK) &PFive.UK=1100|1000=1000

1000==PFive.UK,返回true

所以通过按位运算,可以进行如上的一个简单判断。

这里需要提一下,为什么我们不能用普通的枚举值呢?很简单,如果Russia=1,China=2,USA=3,那么3可以代表USA,也可以代表Russia和China两个国家,这会造成一种混乱。
posted on 2015-08-20 20:20  Figgy  阅读(2885)  评论(9编辑  收藏  举报