剖析 微博短链接算法 里的 位运算 操作
2013-10-21 20:22
302 查看
本文主要写给对 java 位运算不是很了解的童鞋 和 我自己
昨天研究了一下微博短链接的算法,但是发现自己对算法里面的位运算不是很明白,所以有了今天这篇文章
微博短链接生成算法:http://blog.csdn.net/wgw335363240/article/details/6568794
在这里我们看到的第一个有关位运算的是
首先我们看看0x3FFFFFFF的2进制打印处理的结果是什么?
而接下来我们要先说一下 & 这个在java里的 位操作
& 与:当两边结果相等,结果为真,否则为0
例子:
5&3=1
5: 0000 0000 0000 0000 0000 0000 0000 0101
3: 0000 0000 0000 0000 0000 0000 0000 0011
0000 0000 0000 0000 0000 0000 0000 0001
-5&3=3
-5: 1111 1111 1111 1111 1111 1111 1111 1011
3: 0000 0000 0000 0000 0000 0000 0000 0011
0000 0000 0000 0000 0000 0000 0000 0011
你会看到上面的结果运算逻辑
那我们来看看一个从32位md5串里取出来的8位md5串和0x3fffffff 的运算结果是什么?
假设我的md5值为098f6bcd4621d373cade4e832627b4f6,取到第一个8位md5: 098f6bcd
下面运算过程
最后你发现结果居然没变,为什么呢?因为我们的0x098f6bcd的二进制位书并没有超过30位
那我们换一个来看看,假设运算md5串为0xf98f6bcd,我把首位的0换成f
预算过程
通过上面的运算,你会发现,如果是一个数超过了 30 位,把它和0x3fffffff进行&与操作,那就可以截取前面30位的数了
下面我们来看算法里面的第二个位操作
那我们来看看0x0000003D的二进制和十进制数值
想多了还不如我们来实践一下,我们刚刚0x098F6BCD通过了0x3FFFFFF的&操作,结果是不变的,还是0x098F6BCD
那我们直接和 0x0000003D 进行 & 操作
那我们明显的看到任何一个数和
0x0000003D进行&与操作之后得到的值都不会超过61(要知道0x098F6BCD的10进制值是160394189)
,那我们就明白一开始代码的意思了,和0x0000003D进行&与操作是为了将这个值提取成一个大于61的值
So magical !....
最后补充关于>>操作符的一点点
移位运算符
包括:
“>> 右移”;“<< 左移”;“>>> 无符号右移”
例子:
-5>>3=-1 (将-5右移3位)
1111 1111 1111 1111 1111 1111 1111 1011
1111 1111 1111 1111 1111 1111 1111 1111
其结果与 Math.floor((double)-5/(2*2*2)) 完全相同。
-5<<3=-40 (将-5左移3位,移动后补0)
1111 1111 1111 1111 1111 1111 1111 1011
1111 1111 1111 1111 1111 1111 1101 1000
其结果与 -5*2*2*2 完全相同。
PS:总的来说,对于我这个没接触过java位运算的人来说,&与操作实在是太神奇了,一开始有点理解不能
昨天研究了一下微博短链接的算法,但是发现自己对算法里面的位运算不是很明白,所以有了今天这篇文章
微博短链接生成算法:http://blog.csdn.net/wgw335363240/article/details/6568794
在这里我们看到的第一个有关位运算的是
// 这里需要使用 long 型来转换,因为 Inteper .parseInt() 只能处理 31 位 , 首位为符号位 , 如果不用 long ,则会越界 // 将 lHexLong 16进制串 与 0x3fffffff(30位1) 进行 与(&) 操作,即将 lHexLong 超过 30位 的进行忽略处理; long lHexLong = 0x3FFFFFFF & Long.parseLong (sTempSubString, 16);这里为什么会用 0x3FFFFFFF & sTempSubString 进行一个超过30位的忽略处理呢?
首先我们看看0x3FFFFFFF的2进制打印处理的结果是什么?
System.out.println("16f2:"+Long.toBinaryString(0x3fffffff)); 结果:111111111111111111111111111111我们发现它是一个30位 1 组成的一个2 进制串
而接下来我们要先说一下 & 这个在java里的 位操作
& 与:当两边结果相等,结果为真,否则为0
例子:
5&3=1
5: 0000 0000 0000 0000 0000 0000 0000 0101
3: 0000 0000 0000 0000 0000 0000 0000 0011
0000 0000 0000 0000 0000 0000 0000 0001
-5&3=3
-5: 1111 1111 1111 1111 1111 1111 1111 1011
3: 0000 0000 0000 0000 0000 0000 0000 0011
0000 0000 0000 0000 0000 0000 0000 0011
你会看到上面的结果运算逻辑
那我们来看看一个从32位md5串里取出来的8位md5串和0x3fffffff 的运算结果是什么?
假设我的md5值为098f6bcd4621d373cade4e832627b4f6,取到第一个8位md5: 098f6bcd
下面运算过程
//获取098f6bcd的二进制值System.out.println("16f2:"+Long.toBinaryString(0x098f6bcd)); 结果:1001100011110110101111001101 //上面说过,我们已经获得了0x3fffffff的二进制值 //我们现在直接 & 与操作比较,要注意,比较的位数不够,前面直接补0 //例如 1001100011110110101111001101 补齐30位的结果就是 001001100011110110101111001101 0x3fffffff: 111111111111111111111111111111 0x098f6bcd: 001001100011110110101111001101 result : 001001100011110110101111001101 result_16+: 098f6bcd 运算代码 System.out.println("16f2:"+Long.toBinaryString(0x3fffffff & 0x098f6bcd));
最后你发现结果居然没变,为什么呢?因为我们的0x098f6bcd的二进制位书并没有超过30位
那我们换一个来看看,假设运算md5串为0xf98f6bcd,我把首位的0换成f
预算过程
//获取f98f6bcd的二进制值 System.out.println("16f2:"+Long.toBinaryString(0xf98f6bcd)); 结果:1111111111111111111111111111111111111001100011110110101111001101 &与运算,运算时补齐0x3fffffff的位数 0x3fffffff: 0000000000000000000000000000000000111111111111111111111111111111 0xf98f6bcd: 1111111111111111111111111111111111111001100011110110101111001101 result : 0000000000000000000000000000000000111001100011110110101111001101 运算代码 System.out.println("16f2:"+Long.toBinaryString(0x3fffffff & 0xf98f6bcd));
通过上面的运算,你会发现,如果是一个数超过了 30 位,把它和0x3fffffff进行&与操作,那就可以截取前面30位的数了
下面我们来看算法里面的第二个位操作
//把得到的值与0x0000003D进行位与运算,取得字符数组chars索引 int index = 0x0000003D & hexint;这里是为了将hexint转换成chars字符串数组的索引,以方便从 chars取到字符串然后拼接成短链接
那我们来看看0x0000003D的二进制和十进制数值
System.out.println("16f2:"+Long.toBinaryString(0x0000003D)); 二进制结果:111101 System.out.println("16f10:"+Long.parseLong("0000003D",16)); 十进制结果:61看到61这个数值,我们好像明白了点什么?chars的长度不就是62么?那它的索引最大值就是61咯
想多了还不如我们来实践一下,我们刚刚0x098F6BCD通过了0x3FFFFFF的&操作,结果是不变的,还是0x098F6BCD
那我们直接和 0x0000003D 进行 & 操作
//获取0x0000003D和0x098F6BCD的二进制值 System.out.println("16f2:"+Long.toBinaryString(0x0000003D)); System.out.println("16f2:"+Long.toBinaryString(0x098F6BCD)); 结果1: 111101 结果2: 1001100011110110101111001101 &与运算,运算时补齐0x0000003D的位数 0x0000003D: 0000000000000000000000111101 0x098F6BCD: 1001100011110110101111001101 result : 0000000000000000000000001101 result_10+: 13 运算代码 System.out.println("16f2:"+Long.toBinaryString(0x3fffffff & 0xf98f6bcd));从上面的运算结果看到, 0x098F6BCD和0x0000003D进行与操作之后的2进制结果是1101,而10进制结果是13
那我们明显的看到任何一个数和
0x0000003D进行&与操作之后得到的值都不会超过61(要知道0x098F6BCD的10进制值是160394189)
,那我们就明白一开始代码的意思了,和0x0000003D进行&与操作是为了将这个值提取成一个大于61的值
So magical !....
最后补充关于>>操作符的一点点
移位运算符
包括:
“>> 右移”;“<< 左移”;“>>> 无符号右移”
例子:
-5>>3=-1 (将-5右移3位)
1111 1111 1111 1111 1111 1111 1111 1011
1111 1111 1111 1111 1111 1111 1111 1111
其结果与 Math.floor((double)-5/(2*2*2)) 完全相同。
-5<<3=-40 (将-5左移3位,移动后补0)
1111 1111 1111 1111 1111 1111 1111 1011
1111 1111 1111 1111 1111 1111 1101 1000
其结果与 -5*2*2*2 完全相同。
PS:总的来说,对于我这个没接触过java位运算的人来说,&与操作实在是太神奇了,一开始有点理解不能
相关文章推荐
- 性能中的内存分析要注意的地方
- c运行库简介
- 急救啊,c++的一个字符串中删除指定的字符串,
- 学习设计模式之禅——代理模式
- progressBar自定义图片(圈圈等待)
- hdoj 1166 敌兵布阵 线段数和树状数组
- plist Bundle
- Oracle用户、权限、角色管理
- memorydump()输出内存单元地址的数据
- robotium 方法学习实例
- A simple problem(hdu2522)
- ExtJS的使用方法汇总—配置和表格控件使用
- 性能测试必备SQL语句总结
- jQuery 中 each()方法的讲解
- I/O控制方式
- 类的成员函数参数定义为类的对象(匿名对象)
- oracle创建表空间 删除表空间 创建用户 删除用户相关SQL
- 在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解)
- Google云计算三大核心技术之HBase
- 简单测试Newtonsoft.json JObject内存占用分配