热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

位运算中的异或运算

位运算是非常迅速的,因为它直接对内存中的二进制数据进行操作。按位运算除了,按位与,按位非,按位左移,按位右移,还有按位异或。按位异或运算定义,1^101^010^110^00

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

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


按位异或运算定义,

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 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 // 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 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 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
//#include
#include
#include

#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 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 // 请在此处补全代码 - 开始
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亿的搜索引擎!!!!!


 



推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
author-avatar
王强丫ES
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有