位运算中的异或运算

位运算是非常迅速的,因为它直接对内存中的二进制数据进行操作。 

按位运算除了,按位与,按位非,按位左移,按位右移,还有按位异或。


按位异或运算定义,

1 ^ 1=0

1 ^ 0=1

0 ^ 1=1

0 ^ 0=0

异或,就是“看看你们到底一样不一样。不一样就为1,一样就为0。”

 

按位异或运算的规律是

定理一a ^ b = b ^ a

定理二 a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;

定理三 a ^ b ^ a = b, a ^ a^ b = b, b ^ a^ a = b

定理四若d = a ^ b ^ c,则a = d ^ b ^ c

证明:

在d = a ^ b ^ c两边同时异或^ b ^ c,得

d ^ b ^ c =a ^ b ^ c ^ b ^ c

d ^ b ^ c =a ^ b ^ b ^ c ^ c,由定理三得

d ^ b ^ c =a ^ c ^ c,同样由定理三得

d ^ b ^ c =a

 

 

异或的几个常见用途:

(1) 实现两个值的交换,而不必使用临时变量。

    例如交换两个整数a=10100001,b=00000110的值,可通过下列语句实现:

    a = a^b;  //a=10100111

    b = b^a;  //b=10100001

    a = a^b;  //a=00000110

 

(2) 在汇编语言中经常用于将变量置零:

   xor   a,a

 

(3) 使某些特定的位翻转

    例如对数10100001的第2位和第3位翻转,则可以将该数与00000110进行按位异或运算。

       10100001^00000110 = 10100111

 

(4)使用定理三进行编码解码

由B ^ A^ A = B,我们可以假设一聊天记录是B,密钥是A。现在B ^ A之后,成了密文了。为了解密,对密文再使用密钥A进行一次异或运算即可。也即是B ^ A^ A = B。


看看今年SOGOU校招在线测试的一道编码解码题目。原题(JAVA版本)如下

public class Test {

    public static void encode(byte[] in, byte[] out, int password) {
        int len = in.length;

        int seed = password ^ 0x3e1e25e6;
        for (int i = 0; i < len; ++i) {
            byte a = (byte) ((in[i] ^ seed) >> 3);
            byte b = (byte) (((((int) in[i]) << 18) ^ seed) >>> (18 - 5));
            a &= 0x1f;
            b &= 0xe0;
            out[i] = (byte) (a | b);
            seed = (seed * 84723701 ^ seed ^ out[i]);
        }
    }

    public static void decode(byte[] in, byte[] out, int password) {
        int len = in.length;
        int seed = password ^ 0x3e1e25e6;
        for (int i = 0; i < len; ++i) {
            // fill the code here
        }
    }

    public static void main(String[] args) throws Exception {
        int password = 0xfdb4d0e9;
        byte[] buf1 = { -5, 9, -62, -122, 50, 122, -86, 119, -101, 25, -64,
                -97, -128, 95, 85, 62, 99, 98, -94, 76, 12, 127, 121, -32,
                -125, -126, 15, 18, 100, 104, -32, -111, -122, 110, -4, 60, 57,
                21, 36, -82, };
        byte[] buf2 = new byte[buf1.length];
        decode(buf1, buf2, password);
        System.out.println(new String(buf2, "GBK"));
    }
}

题目要求补充decode函数。那么根据encode函数就可以补充decode函数。解题要点是位运算中的左移,右移,按位与,按位异或,按位异或定理三。


 先来理解encode函数。

public static void encode(byte[] in, byte[] out, int password) {
        int len = in.length;

        int seed = password ^ 0x3e1e25e6;
        for (int i = 0; i < len; ++i) {
            byte a = (byte) ((in[i] ^ seed) >> 3);
            //说明①: in[i]的高5位给了a的低5位
            byte b = (byte) (((((int) in[i]) << 18) ^ seed) >> (18 - 5));
            //说明②: in[i]的低3位给了b的高3位
            a &= 0x1f;
            //0x1f=16+15=31=2^5-1=00011111;
            b &= 0xe0;
            //0xe0=11100000;
            out[i] = (byte) (a | b);
            seed = (seed * 84723701 ^ seed ^ out[i]);
        }
    }


然后就可以编写decode函数了

    public static void decode(byte[] in, byte[] out, int password) {
        int len = in.length;// encode中的out[i]是这里decode中的in[i]
        int seed = password ^ 0x3e1e25e6;
        for (int i = 0; i < len; ++i) {
        	byte a = (byte) (in[i] & 0x1f);
//参照式⑤,还原输出结果,取in[i]的低5位
        	byte b = (byte) (in[i] & 0xe0); 
//参照式⑤,还原输出结果,取in[i]的高3位
        	a = (byte) (((a <<3) ^ seed) & 248); 
//参照定理三B ^ A^ A = B,参照式①byte a = (byte) ((in[i] ^ seed) >>> 3)
//式①中的in[i]相当于B,seed相当于A,(a<<3)相当 B ^ A 故((a <<3) ^ seed)表示in[i]高5
//位的这5个数字,为了将这5个数字放入高5位的位置上,还需&11111000,即&248。
//11111000=2^7+2^6+2^5+2^4+2^3=128+64+32+16+8=248
        	b = (byte) ((((((int) b) << (18 - 5)) ^ seed) >> 18) & 7);
//类似地,逆向式②,得到的结果将放入out[i]的低3位,故&00000111,即&7。
//00000111=2^0+2^1+2^2=1+2+4=7
        	out[i] = (byte) (a | b);
        	seed = (seed * 84723701 ^ seed ^ in[i]);
        }
    }

//最后的输出答案微雷,答案是“真双核引擎是全球最快的浏览器内核!!!!”


这道题还有C++版本的,几乎和JAVA版本一模一样。

#include "stdafx.h"
#include <stdio.h>  
//#include <stdlib.h>  
#include <assert.h>  
#include <string.h>  

#define uint8_t unsigned char  
#define uint32_t unsigned int  
#define size_t unsigned int 


int  encode(const  void*  raw_in,  void*  raw_out,  uint32_t  password,  size_t  len) 
{ 
const  uint8_t*  in  =  (const  uint8_t*)raw_in; 
uint8_t*  out  =  (uint8_t*)raw_out; 

uint32_t  seed  =  password  ^  0x3feb3c98u; 
for  (size_t  i  =  0  ;  i  <  len;  ++i)  { 
uint8_t  a  =  (  in[i]  ^  seed  )  >>  4; 
uint8_t  b  =  (  (  ((uint32_t)in[i])  <<  17  )  ^  seed  )  >>  (17-4); 
a  &=  15;  //00001111
b  &=  240; //11110000=2^7+2^6+2^5+2^4=128+64+32+16=240
a  =  15  &  (  a  ^  (b  <<  3)); 
out[i]  =  a  |  b; 
seed  =  (seed  *  48475829  ^  seed  ^  in[i]); 
} 
return 0;
} 


int  decode(const  void*  raw_in,  void*  raw_out,  uint32_t  password,  size_t  len) 
{ 
const  uint8_t*  in  =  (const  uint8_t*)raw_in; 
uint8_t*  out  =  (uint8_t*)raw_out; 

uint32_t  seed  =  password  ^  0x3feb3c98u; 
for  (size_t  i  =  0  ;  i  <  len;  ++i)  { 
//  请在此处补全代码 - 开始
	uint8_t a=in[i]&15;
	uint8_t b=in[i]&240;
	a=((a<<4)^seed)&240;
	b=((((uint32_t)b<<13)^seed)>>17)&15;
	out[i]  =  a  |  b; 
	seed  =  (seed  *  48475829  ^  seed  ^  out[i]); 
//  请在此处补全代码 - 结束
} 
return 0;
} 
int  main() 
{ 
const  uint8_t  buf1[]  =  {0x1e,  0x7b,  0x8f,  0x63,  0x6f,  0x69,  0x26,  0x23,  0x64,  0xe1,  0x09,  0x21,  0x13,  0x2b,  0x37,  0xdf,  0xa4,  0x7f,  0x45,  0xe3,  0x6b,  0xda,  0x6a,  0x00,  0x93,  0x4b,  0xd1,  0x81,  0x92,  0x20,  0x69,  0x74,  0xf9,  0xf1,  0x1f,  0xb9,  0x1f,  0x6d,  0x20,  0x7b,  0xe8,  0x0c,  0x89,  0x29,  0x77,  0x65,  0xaa,  0x0f,  0xdb,  0x45,  0x4e,  0x58,  0x39,  0x98,  0x7f,  0xa7,  0x04,  0x71,  0xb4,  0xe1,  0xe4,  }; 
uint8_t  buf2[100]  = ""; 
const  uint32_t  password  =  0xe53e6eb6u; 
const  size_t  len  =  sizeof(buf1); 
decode(buf1,  buf2,  password,  len); 
printf("%s\n",  buf2); 
return 0;
} 

//输出答案:搜狗搜索是全球首个中文网页收录量达到100亿的搜索引擎!!!!!


 

 

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值