好的,这里有一些关于这个问题的想法。
假随机函数通常称为伪随机数生成器 (PRNG)。
您可能对 [0...1) 范围内的双精度数感兴趣,但 PRNG 通常会生成单个 64 位(适用于双精度)或 32 位(适用于浮点数)整数。转换为 double 虽然不是很简单,但操作相当简单。
典型的 PRNG 具有状态、用种子启动和输出。对于最简单的 PRNG(如 LCG)种子,状态和输出是一回事,但一般情况下并非如此。通常状态以位数为特征(例如,LCG 为 64 位,Mersenne twister 为 19937 位)。
从任何 PRNG 算法生成纯函数都相当简单——PRNG 只是一组三个函数,形式为
state_type make_state(seed_type seed) {
// convert seeding to state, bits chopping
return new_state;
}
state_type advance_state(state_type old_state) {
// do bits chopping with old state
// and advance to the next state
return new_state;
}
uint64_t generate_output(state_type state) {
// extract 64bits of randomness from state
return new_random_number;
}
就是这样,除了这些功能之外,PRNG 中没有其他内容了。
而且,对于手头的问题
您可以使用具有良好Avalanche 属性的非加密哈希,基本上意味着输入值的单个位变化(输入增加 1)会导致输出发生很大变化。快速,合理,可能不是很随机。杂音还可以,还有妈妈哈希。
以计数器模式运行的加密密码。比选项 1 慢,但数字质量高。相对较大的状态(比如 512 位左右)。我更喜欢ChaCha20 - 它是众所周知的,合理的快速,看看这里的代码。选项 1 和 2 都假设您只有线性增加的计数器作为输入。
另一种选择是使用具有对数复杂度跳转功能的 PRNG。这你可以从全局种子开始,如果你有 2 10 个CUDA 核心,你的第一个核心将使用种子,第二个将向前跳跃 2 64 /2 10 =2 54,复杂度为 O(log 2 (N))只有 54 次操作,第三次将领先第二次另外 2 54步和 54 次操作,依此类推。在已知的 PRNG 中,对数跳转适用于 LCG 和PCG。我建议看看PCG。
这意味着存在以下形式的非平凡函数
state_type advance_state(state_type old_state, int64_t distance) {
// non-trivial advance by distance
// non-trivial means it is not just a loop, it is better than linear algorithm
return new_state;
}