位运算 之----------(2)------- 按位异或(xor)^ 操作

转自:http://www.cnblogs.com/ktyanny/archive/2009/12/25/1632401.html

 

按位异或运算

 俗称:xor运算

 

1、xor的基本知识

 

我们来看看xor运算的机理:

 

         1001011001011----àa

xor    1011010001110----àb

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

         0010001000101---àc

 

看了上面的式子,体会到异或运算的原理了吧,就是:0和1异或0都不变,异或1则取反。很容易理解,如果b中的某位为1,那么a xor b 的作用是在a相应的位进行取反操作。用通俗易懂的语言来讲就是xor运算通常用于对二进制的特定一位进行取反操作。

我们再看到上面那个计算式子,如果得到的结果c再与b做异或运算即:

   0010001000101---àc

xor    1011010001110---àb

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

         1001011001011---àd

 

注意到了吧,a == d  是成立的!那么我们可以得到一个结论:(a xor b) xor b = a。

同时我们还可以得到一个swap操作:

a  ^=  b;  b ^= a; a ^= b;

自己拿起笔来模拟一下就很清楚的了。

 

2、xor和 not (按位否)操作之间的关系

事实上很简单,nor操作是xor操作的一个特例。取反实质上就是同1做异或操作

~x =  x^0x FFFFFFFF

 

3、两个比较有趣的式子:(n ^(n+1)) 和 ((n ^(n-1))+1)>>1

(1)首先来看(n ^(n+1))这个式子,假设n = 10011010, n+1 = 10011011,则:

     10011010---àn

xor    10011011---àn+1

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

         00000001---àans

如果还不能看出什么的话,再来一个例子:n = 11111111, n+1 = 100000000,则:

    11110111---àn

xor     11111000---àn+1

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

          000001111---àans

得到的结果为n的倒数出现第一个0的位以及后面所有的1全部变成1,其它位都为0的数。

 

 

(2)再来看看((n ^(n-1))+1)>>1这个式子

假设n = 10011010, n-1 = 10011001,则:

 

10011010---àn

xor    10011001---àn-1

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

      00000011---àans

ans+1 >> 1  = 000000100 >> 1 = 000000010

 

看出来了吧,也就是取出n出现倒数第一个1的位及该位后面的0组成的数

 

4、统计n中1的奇偶性

思路:我们在按位与运算的时候学过了怎么计算一个整数中1的个数,但是我们现在用xor来解决吧:

x = x ^ (x>>1);
x = x ^ (x>>2);
x = x ^ (x>>4);
x = x ^ (x>>8);
x = x ^ (x>>16);
return x&1;

说道这里,顺便提一下怎么求解一个数n的前导0的个数,下面的代码来自Hacker's Delight

 
int nlz(unsigned x)
{
int n;
if (x == 0) return(32);
   n = 1;
   if ((x >> 16) == 0) {n = n +16; x = x <<16;}
   if ((x >> 24) == 0) {n = n + 8; x = x << 8;}
   if ((x >> 28) == 0) {n = n + 4; x = x << 4;}
   if ((x >> 30) == 0) {n = n + 2; x = x << 2;}
   n = n - (x >> 31);
   return n;
}//代码自己慢慢理解吧
 

 

 

参与运算的两个值,如果两个相应bit位相同,则结果为0,否则为1。
即:
   0^0 = 0, 
      1^0 = 1, 
      0^1 = 1, 
      1^1 = 0
按位异或的3个特点:
(1) 0^0=0,0^1=1  0异或任何数=任何数
(2) 1^0=1,1^1=0  1异或任何数-任何数取反
(3) 任何数异或自己=把自己置0
按位异或的几个常见用途:
(1) 使某些特定的位翻转
    例如对数10100001的第2位和第3位翻转,则可以将该数与00000110进行按位异或运算。
       10100001^00000110 = 10100111

(2) 实现两个值的交换,而不必使用临时变量。
    例如交换两个整数a=10100001,b=00000110的值,可通过下列语句实现:
    a = a^b;   //a=10100111
    b = b^a;   //b=10100001
    a = a^b;   //a=00000110

(3) 在汇编语言中经常用于将变量置零:
    xor   a,a

(4) 快速判断两个值是否相等
    举例1: 判断两个整数a,b是否相等,则可通过下列语句实现:
        return ((a ^ b) == 0)
    
    举例2: Linux中最初的ipv6_addr_equal()函数的实现如下:
    static inline int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2)
    {
        return (a1->s6_addr32[0] == a2->s6_addr32[0] &&
            a1->s6_addr32[1] == a2->s6_addr32[1] &&
            a1->s6_addr32[2] == a2->s6_addr32[2] &&
            a1->s6_addr32[3] == a2->s6_addr32[3]);
    }
    
    可以利用按位异或实现快速比较, 最新的实现已经修改为:
    static inline int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2)
    {
    return (((a1->s6_addr32[0] ^ a2->s6_addr32[0]) |
        (a1->s6_addr32[1] ^ a2->s6_addr32[1]) |
        (a1->s6_addr32[2] ^ a2->s6_addr32[2]) |
        (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0);
    }

5  应用通式:

对两个表达式执行按位异或。

result = expression1 ^ expression2

参数
result

任何变量。

expression1

任何表达式。

expression2

任何表达式。

说明
^ 运算符查看两个表达式的二进制表示法的值,并执行按位异或。该操作的结果如下所示:

0101     (expression1)1100     (expression2)----1001     (结果)当且仅当只有一个表达式的某位上为 1 时,结果的该位才为 1。否则结果的该位为 0。

只能用于整数

 


下面这个程序用到了“按位异或”运算符:

class E 
{ public static void main(String args[ ]) 

  char  a1='十' ,  a2='点' ,  a3='进' ,  a4='攻' ; 
  char secret='8' ; 
  a1=(char) (a1^secret); 
  a2=(char) (a2^secret); 
  a3=(char) (a3^secret); 
  a4=(char) (a4^secret); 
  System.out.println("密文:"+a1+a2+a3+a4); 
  a1=(char) (a1^secret); 
  a2=(char) (a2^secret); 
  a3=(char) (a3^secret); 
  a4=(char) (a4^secret); 
  System.out.println("原文:"+a1+a2+a3+a4); 

}

就是加密啊解密啊

char类型,也就是字符类型实际上就是整形,就是数字.

计算机里面所有的信息都是整数,所有的整数都可以表示成二进制的,实际上计算机只认识二进制的. 
位运算就是二进制整数运算啦. 
两个数按位异或意思就是从个位开始,一位一位的比. 
如果两个数相应的位上一样,结果就是0,不一样就是1 
所以111^101=010 
那加密的过程就是逐个字符跟那个secret字符异或运算. 
解密的过程就是密文再跟同一个字符异或运算 
010^101=111 
至于为什么密文再次异或就变原文了,这个稍微想下就知道了..

posted @ 2013-05-26 16:06  cq-home  Views(2806)  Comments(0Edit  收藏  举报