与&运算
0376的二进制就是1111 1110,二进制的与运算规则是,只有两个数同时为1时,则结果才为1,只要有一个数为0,则结果就为0。比如1&1=1; 1&0=0; 0&1=0; 0&0=0;因此把一个字符与二进制1111 1110进行与运算的结果就是把最后位设为0,而其他位不变。作个比喻假设a的二进制表示为1010 0111我们先不管这个数表示的是什么,我们来把这个数与1111 1110进行按位与运算,看看结果。
t_zset.c
#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
#define ZSKIPLIST_P 0.25 /* Skiplist P = 1/4 */int zslRandomLevel(void) {
int level = 1;
while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
level += 1;
return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}
0xFFFF=1111 1111 1111 1111
任何数和0xFFFF与运算其实就是暗含高位清零,低位与 结果就是一个0和65535之间的数
ZSKIPLIST_P * 0xFFFF=0.25*65535 肯定是比65535小 ,
所以系数ZSKIPLIST_P越小 ,((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))是1的可能就越大,就会继续while
(random()&0xFFFF) 本身就有50%的概率是0 0肯定小于ZSKIPLIST_P * 0xFFFF
$485 = 0
(gdb)
$486 = 1
(gdb)
$487 = 0
(gdb)
$488 = 1
(gdb)
$489 = 0
(gdb)
$490 = 0
(gdb)
$491 = 0
(gdb)
$492 = 0
(gdb)
$493 = 0
(gdb)
$494 = 1
10次有3次是1 30%的概率接近25%
类似的
zmalloc.c
#define update_zmalloc_stat_alloc(__n) do { \
size_t _n = (__n); \
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
if (zmalloc_thread_safe) { \
update_zmalloc_stat_add(_n); \
} else { \
used_memory += _n; \
} \
} while(0)
#define update_zmalloc_stat_free(__n) do { \
size_t _n = (__n); \
if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \
if (zmalloc_thread_safe) { \
update_zmalloc_stat_sub(_n); \
} else { \
used_memory -= _n; \
} \
} while(0)

本文深入探讨了Redis源码中zslRandomLevel函数的位运算逻辑,特别是`random() & 0xFFFF`与`ZSKIPLIST_P * 0xFFFF`的比较,揭示了如何通过位运算控制跳表层数生成的概率,以确保在高效与空间利用率之间取得平衡。

1156

被折叠的 条评论
为什么被折叠?



