偶然发现一个平均分布得不可思议的伪随机函数

起因是我在构思哈希表的结构,不想用链表处理冲突,那么就必须找一个伪随机函数,如果哈希值n对应的数组位置有值了,那么循环执行n=函数(n),直到n对应位置为空,函数必须足够“分散”,也就是每次调用结果“激烈跳动”,比如n=n+1显然不合适,也必须是“伪”的,也就是同样的输入值,算出的结果必须一样。于是我查到了LCG算法,比如这里:https://www.cnblogs.com/vancasola/p/9951686.html,我构想的数组长度是2的整数倍,这样取余数用“与”操作很方便,然后写了一个简单的程序测试循环调用随机函数结果的分布:

#include <stdio.h>
#define len (1 << 6)
#define mask (len - 1)
int main() {
    printf("%X %X\n", len, mask);
    int arr[len] = {0};
    int n = 1;
    for (int i = 0; i < len; i++) {
        arr[n]++;
        n = (n * 5 + 1) & mask;
    }
    for (int i = 0; i < len; i++) {
        printf("%d\t%d\n", i, arr[i]);
    }
    return 0;
}

然后我就发现了一个奇怪的现象,依文章里讲的那些取值根本不行,值都集中在几个位置,但是n*5+1却非常神奇地完美覆盖了数组的每一个位置,也就是循环len次,数组每个位置都是完美的1,如果把循环次数减少,也会发现分布足够均匀,而且我测试了不同的2的次方的数组长度,发现没有例外。另外,+3 +5 +7 +11都可以,好像是素数?我数学不好,这个现象能从数学上证明吗?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值