学习redis 字典结构,hash找槽位 求槽位的索引值时,用到了 hash值 & sizemask操作,

其后的scan操作涉及扫描顺序逻辑,对同模的槽位 按一定规则扫描!

其中涉及位运算 & 和 %操作之间的关系!故整理学习资料如下:

原文引自:http://blog.sina.com.cn/s/blog_7b7cad23010163vy.html

由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。

按位与(Bitwise AND),运算符号为&

a&b 的操作的结果:a、b中对应位同时为1,则对应结果位也为1、

例如:

10010001101000101011001111000

&           111111100000000

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

                    10101100000000

对10101100000000进行右移8位得到的是101011,这就得到了a的8~15位的掩码了。

那么根据这个启示,判断一个整数是否是处于 0-65535(2^16) 之间(常用的越界判断):

用一般的 (a >= 0) && (a <= 65535) 可能要两次判断。

改用位运算只要一次:

a & ~((1<< 16)-1)

Ex:
1 0000 0000 0000 0000 //1 << 16 = 65536
0 1111 1111 1111 1111 //(1 << 16) -1 = 65535
1111 11... 0000 0000 0000 0000        //上一步结果~运算,高位都置1,小于65536的位置0, a & 1111 .. 0000 0000 0000 0000             //为真,说明高位有值,大于65535

  

后面的常数是编译时就算好了的。其实只要算一次逻辑与就行了。

常用技巧:

1、 用于整数的奇偶性判断

一个整数a, a & 1 这个表达式可以用来判断a的奇偶性。二进制的末位为0表示偶数,最末位为1表示奇数。使用a%2来判断奇偶性和a & 1是一样的作用,但是a & 1要快好多。

2、 判断n是否是2的正整数冪

(!(n&(n-1)) )&& n

举个例子:

如果n = 16 = 10000, n-1 = 1111

那么:

10000

& 1111

----------

           0

再举一个例子:如果n = 256 = 100000000, n-1 = 11111111

那么:

100000000

&11111111

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

0

好!看完上面的两个小例子,相信大家都有一个感性的认识。从理论上讲,如果一个数a他是2的正整数幂,那么a 的二进制形式必定为1000…..(后面有0个或者多个0),那么结论就很显然了。

3、 统计n中1的个数

朴素的统计办法是:先判断n的奇偶性,为奇数时计数器增加1,然后将n右移一位,重复上面步骤,直到移位完毕。

朴素的统计办法是比较简单的,那么我们来看看比较高级的办法。

举例说明,考虑2位二进制数 n=11,里边有2个1,先提取里边的偶数位10,奇数位01,把偶数位右移1位,然后与奇数位相加,因为每对奇偶位相加的和不会超过“两位”,所以结果中每两位保存着数n中1的个数;相应的如果n是四位整数 n=0111,先以“一位”为单位做奇偶位提取,然后偶数位移位(右移1位),相加;再以“两位”为单位做奇偶提取,偶数位移位(这时就需要移2位),相加,因为此时没对奇偶位的和不会超过“四位”,所以结果中保存着n中1的个数,依次类推可以得出更多位n的算法。整个思想类似分治法。
在这里就顺便说一下常用的二进制数:

0xAAAAAAAA=10101010101010101010101010101010

0x55555555 = 1010101010101010101010101010101(奇数位为1,以1位为单位提取奇偶位)

0xCCCCCCCC = 11001100110011001100110011001100

0x33333333 = 110011001100110011001100110011(以“2位”为单位提取奇偶位)

0xF0F0F0F0 = 11110000111100001111000011110000

0x0F0F0F0F = 1111000011110000111100001111(以“8位”为单位提取奇偶位)

0xFFFF0000 =11111111111111110000000000000000

0x0000FFFF = 1111111111111111(以“16位”为单位提取奇偶位)

例如:32位无符号数的1的个数可以这样数:

 
int
count_one(unsigned
long n)
{
//0xAAAAAAAA,0x55555555分别是以“1位”为单位提取奇偶位
n = ((n & 0xAAAAAAAA) >>
) + (n & 0x55555555);

//0xCCCCCCCC,0x33333333分别是以“2位”为单位提取奇偶位
n = ((n & 0xCCCCCCCC) >>
) + (n & 0x33333333);

//0xF0F0F0F0,0x0F0F0F0F分别是以“4位”为单位提取奇偶位
n = ((n & 0xF0F0F0F0) >>
) + (n & 0x0F0F0F0F);

//0xFF00FF00,0x00FF00FF分别是以“8位”为单位提取奇偶位
n = ((n & 0xFF00FF00) >>
) + (n & 0x00FF00FF);

//0xFFFF0000,0x0000FFFF分别是以“16位”为单位提取奇偶位
n = ((n & 0xFFFF0000) >>
) + (n & 0x0000FFFF);

return
n;
}

举个例子吧,比如说我的生日是农历2月11,就用211吧,转成二进制:

n =
11010011

计算n = ((n &
0xAAAAAAAA) >> 1) + (n
& 0x55555555);

得到 n = 10010010

计算n = ((n &
0xCCCCCCCC) >> 2) + (n
& 0x33333333);

得到 n = 00110010

计算n = ((n &
0xF0F0F0F0) >> 4) + (n
& 0x0F0F0F0F);

得到 n = 00000101
-----------------à无法再分了,那么5就是答案了。

4、对于正整数的模运算(注意,负数不能这么算)

先说下比较简单的:

乘除法是很消耗时间的,只要对数左移一位就是乘以2,右移一位就是除以2,传说用位运算效率提高了60%。

乘2^k众所周知:
n<<k。所以你以后还会傻傻地去敲2566*4的结果10264吗?直接2566<<4就搞定了,又快又准确。

除2^k众所周知:
n>>k。

那么 mod
2^k
呢?(对2的倍数取模)

n&((1<<k)-1)

用通俗的言语来描述就是,对2的倍数取模,只要将数与2的倍数-1做按位与运算即可。

好!方便理解就举个例子吧。

思考:如果结果是要求模2^k时,我们真的需要每次都取模吗?

在此很容易让人想到快速幂取模法。


快速幂取模算法

经常做题目的时候会遇到要计算 a^b mod
c
的情况,这时候,一个不小心就TLE了。那么如何解决这个问题呢?位运算来帮你吧。

首先介绍一下秦九韶算法:(数值分析讲得很清楚)

把一个n次多项式f(x) =
a[n]x^n+a[n-1]x^(n-1)+......+a[1]x+a[0]改写成如下形式:

  f(x) =
a[n]x^n+a[n-1]x^(n-1))+......+a[1]x+a[0]

  =
(a[n]x^(n-1)+a[n-1]x^(n-2)+......+a[1])x+a[0]

  =
((a[n]x^(n-2)+a[n-1]x^(n-3)+......+a[2])x+a[1])x+a[0]

  =. .....

  =
(......((a[n]x+a[n-1])x+a[n-2])x+......+a[1])x+a[0].

  求多项式的值时,首先计算最内层括号内一次多项式的值,即

  v[1]=a[n]x+a[n-1]

  然后由内向外逐层计算一次多项式的值,即

  v[2]=v[1]x+a[n-2]

  v[3]=v[2]x+a[n-3]

  ......

  v[n]=v[n-1]x+a[0]

这样,求n次多项式f(x)的值就转化为求n个一次多项式的值。

好!有了前面的基础知识,我们开始解决问题吧

由(a
×b) mod c=( (a mod
c)
× b) mod c.

我们可以将 b先表示成就:

b = a[t]

× 2^t +
a[t-1]×
2^(t-1) + …… + a[0]

× 2^0.
(a[i]=[0,1]).

这样我们由 a^b mod c =
(a^(a[t]
× 2^t +
a[t-1]×
2^(t-1)
+
…a[0]
× 2^0) mod
c.

然而我们求 a^( 2^(i+1) ) mod c=(
(a^(2^i)) mod c)^2 mod c .求得。

具体实现如下:

使用秦九韶算法思想进行快速幂模算法,简洁漂亮

 
//
快速计算 (a ^ p) % m
的值
__int64
FastM(__int64 a, __int64 p, __int64 m)
{
if
(p == ) return ;
__int64 r =
a % m;
__int64 k =
;
while (p > )
{
if
((p & )!=)
{
k = (k * r) % m;
}
r = (r * r) % m;
p >>=
;
}
return
(r * k) % m;
}
 

http://acm.pku.edu.cn/JudgeOnline/problem?id=3070

5、计算掩码

比如一个截取低6位的掩码:0×3F
用位运算这么表示:(1<< 6) -
1
这样也非常好读取掩码,因为掩码的位数直接体现在表达式里。

按位或运算很简单,只要a和b中相应位出现1,那么a|b的结果相应位也为1。就不多说了。

6、子集

  枚举出一个集合的子集。设原集合为mask,则下面的代码就可以列出它的所有子集:

  for (i = mask ; i ; i = (i - 1)
& mask) ;

位运算之——按位与(&)操作——(快速取模算法)的更多相关文章

  1. 【Java基础】14、位运算之——按位与(&)操作——(快速取模算法)

    学习redis 字典结构,hash找槽位 求槽位的索引值时,用到了 hash值 & sizemask操作, 其后的scan操作涉及扫描顺序逻辑,对同模的槽位 按一定规则扫描! 其中涉及位运算 ...

  2. 【转】C语言快速幂取模算法小结

    (转自:http://www.jb51.net/article/54947.htm) 本文实例汇总了C语言实现的快速幂取模算法,是比较常见的算法.分享给大家供大家参考之用.具体如下: 首先,所谓的快速 ...

  3. Raising Modulo Numbers_快速幂取模算法

    Description People are different. Some secretly read magazines full of interesting girls' pictures, ...

  4. Educational Codeforces Round 80 C. Two Arrays(组合数快速取模)

    You are given two integers nn and mm . Calculate the number of pairs of arrays (a,b)(a,b) such that: ...

  5. 09 Memcached 分布式之取模算法的缺陷

    一: Memcached 分布式之取模算法的缺陷(1)假设你有8台服务器,运行中突然down一台,则求余数的底数就7. 后果: key_0%8==0 ,key_0%7==0 =>hist(命中) ...

  6. ShardingSphere-proxy-5.0.0企业级分库分表、读写分离、负载均衡、雪花算法、取模算法整合(八)

    一.简要说明 以下配置实现了: 1.分库分表 2.每一个分库的读写分离 3.读库负载均衡算法 4.雪花算法,生成唯一id 5.字段取模 二.配置项 # # Licensed to the Apache ...

  7. Java 位运算(移位、位与、或、异或、非)

    Java提供的位运算符有:左移( << ).右移( >> ) .无符号右移( >>> ) .位与( & ) .位或( | ).位非( ~ ).位异或( ...

  8. 【Java基础】3、Java 位运算(移位、位与、或、异或、非)

    public class Test { public static void main(String[] args) { // 1.左移( << ) // 0000 0000 0000 0 ...

  9. C#位运算实际作用之操作整型某一位

    1.前言 前几天写了两篇关于c#位运算的文章 c#位运算基本概念与计算过程 C#位运算实际运用 在文中也提到了位运算的实际作用之一就是合并整型,当时引用了一个问题: C# 用两个short,一个int ...

随机推荐

  1. 关于JPasswordField的getText()方法过时问题解决

    这几天想做一个登陆界面,用Jframe做,连接数据库时发现JPasswordField的getText()过时了,没法使用.查了资料发现改成了: try{ String sql="SELEC ...

  2. Delphi中打开网页连接的几种方法

    https://blog.csdn.net/zisongjia/article/details/69398143 正好要用,做个记录.Mark下. 使用了第一种 uses shellapi proce ...

  3. c/c++ linux 进程间通信系列3,使用socketpair,pipe

    linux 进程间通信系列3,使用socketpair,pipe 1,使用socketpair,实现进程间通信,是双向的. 2,使用pipe,实现进程间通信 使用pipe关键点:fd[0]只能用于接收 ...

  4. Eclipse出错不断,注册表不能乱改

    Eclipse打不开,始终报错,还能不能开心的敲代码了??? 首先说下造成我这个愚蠢错误的起源:电脑是win10系统,本来是可以正常使用的.某一天,我正在使用python,打开命令提示符,看见开头是中 ...

  5. Python基础之面对对象进阶

    阅读目录 isinstance和issubclass 反射 setattr delattr getattr hasattr __str__和__repr__ __del__ item系列 __geti ...

  6. Python开发【第三篇】基本数据类型

    整型 int __author__ = 'Tang' # 将字符串转换为数字 a = " b = int(a) # 前面是0的数转换,默认base按照十进制 a = " b = i ...

  7. spark-RDD源码分析

    http://stark-summer.iteye.com/blog/2178096 RDD的核心方法: 首先看一下getPartitions方法的源码: getPartitions返回的是一系列pa ...

  8. php使用root用户启动

    一般情况下,肯定是不推荐使用root用户启动php的 但是在某些服务器管理想使用WEB的方式来控制操作的话,那么就必须要使用root用户才有权限操作 1.修改配置文件php-fpm.conf的启动用户 ...

  9. 关键字-super

    super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类. class BaseAction { String name; int age; void value( ...

  10. 【Topcoder 8572】TheLuckySum

    题意:给一个数\(n\),要把它分成lucky numbers的和. 问个数最少.字典序最小的方案. 思路:果断搜索.个数最少,所以迭代加深.枚举要的个数\(m\). 首先我们看\(n\)的个位.它肯 ...