【发布时间】:2018-05-06 10:42:29
【问题描述】:
我正在尝试在 Metal 中创建一个伪随机数生成器 (PRNG),类似于 thrust 的 RNG,每次您在线程中调用 RNG 它都会产生不同的给定特定种子的随机数,在这种情况下,将是thread_position_in_grid。我已经完美地设置了它,我现在使用我拥有的代码得到了一张漂亮的均匀随机图片。
但是,我的代码每个线程只能运行一次。我想实现一个next_rng() 函数,该函数使用最后一个结果作为种子返回一个新的rng。但是,我无法存储最后一个结果,因为我的 RNG 是一个命名空间,并且我只能将最后一个结果存储在不可更新的 constant 地址空间中。有没有办法解决这个问题/重组我的代码以避免这种情况?
我可以在网上找到的最佳帮助是 this SO post,很遗憾,它不适用于我,因为我不能像在他们的解决方案中那样在函数中将变量声明为静态变量。
如果有帮助,我愿意以任何方式重组我的代码。我可以把它变成一个静态类或一个类或什么的吗?不知道,但我只想要一个 PRNG
我的代码(简化版)基本上与那篇文章的结构相同:
namespace metal_rng {
thread unsigned* last_seed() {
thread uint last_seed = 1; // Doesn't work because last-seed falls out of scope after the function quits
// The following comment line doesn't even compile:
// thread static uint last_seed = 1;
return &last_seed;
}
unsigned TausStep(const unsigned z, const int s1, const int s2, const int s3, const unsigned M)
{
unsigned b=(((z << s1) ^ z) >> s2);
return (((z & M) << s3) ^ b);
}
device float rng(const int initial_seed) {
int seed = initial_seed * 1099087573UL;
unsigned hashed = (1664525*(*last_seed()) + 1013904223UL);
*last_seed() = hashed
return (hashed) * 2.3283064365387e-10;
}
device float next_rng() {
if (*last_seed() == 0) {
return 0.0;
} else {
unsigned hashed = (1664525*(*last_seed()) + 1013904223UL);
return (hashed) * 2.3283064365387e-10;
}
}
}
编辑:
框架在这里完成并整齐打包:Link
【问题讨论】:
-
这个RNG代码的客户端代码是什么样子的?您可能应该创建一个类来表示 RNG,其中函数作为成员函数,状态(最后一个种子)作为成员变量。您将在调用代码中创建此类的一个实例作为本地实例,并使用初始种子进行初始化。如果您需要在多个函数中使用它,则必须传递对实例的引用,这很烦人但可行。
-
我将它用于蒙特卡罗路径追踪器。你的建议奏效了!我正在将代码打包成一个简洁的框架供任何人使用。完成后,我将分享一个指向 repo 的链接!非常感谢(:
-
Link to the repo as mentioned before。还有关于如何在 repo 中为任何未来的流浪者使用 RNG 的说明。
标签: c++ random gpu gpgpu metal