我正在尝试实现一个简单的噪声函数,它接受两个整数,并根据种子和两个参数返回一个随机浮点数。
使用std::mt19937
效果很好,但出于某种原因,当我尝试将srand
与rand()
一起使用时,我会重复数字..
注意:在循环中使用c ++ 11
seed
成员函数非常非常慢。
这里有两个使用两种方法的地形(具有相同的重播数字):
c ++ 11 random:
std::random_device rd;
std::mt19937 g{ rd() };
std::uniform_real_distribution<float> gen{ -1.0, 1.0 };
float getNoise(int x, int z) {
g.seed(x * 523234 + z * 128354 + seed);
return gen(g);
}
随机:
float getNoise(int x, int z) {
std::srand(x * 523234 + z * 128354 + seed);
return static_cast<float>(std::rand()) / RAND_MAX * 2.0f - 1.0f;
}
答案 0 :(得分:6)
我正在尝试实现一个简单的噪声函数,它接受两个整数,并根据种子和两个参数返回一个随机浮点数。
请不要说我不应该重新种植,我想故意重新种植。
你故意打破它,并问我们为什么它被打破,但需要注意的是我们不允许在房间里提到大猩猩。
不要重新种植。
[编辑]
好的,根据评论请求,这里有一个答案:
1)不,没有更快的方法来重新种植PRNG,无论如何你都不应该这样做。适当地,你应该播种,然后通过丢弃几千个值来“预热”PRNG。
2)原因rand()
(并且,即使您不相信它,您使用的任何其他PRNG)也不起作用是因为您的getNoise()
功能不正确。
您的第三张图片是正确的。这是应该期望的结果,只需返回一个钳位的随机值。
你试图通过弄乱种子来调节它,并且由于你第一次尝试中的明显视觉上的好处,得出的结论是这是正确的方法。然而,真正发生的事情是你只是削弱了PRNG并看到了结果。 (在rand()
尝试中更清楚,因为它的种子更粗略地定义了结果序列,它本身的周期比Mersenne Twister小。)
(尝试通过倾斜(x,z)坐标来修改它也是一个红色的鲱鱼。它不会影响输出的实际随机性。)
<强> TL; DR 强>
你做错了。
如果你想生成地形图,你应该围绕分形地形生成谷歌。事实上,这里有一个不错的链接:http://www.gameprogrammer.com/fractal.html
你会发现它需要做更多的工作,但这些方法非常简单,你可以很容易地调整它们来修改你的结果。
希望这有帮助。
答案 1 :(得分:3)
随机数生成器从初始种子生成随机值的序列,并不意味着用于生成种子函数的单个随机值。所以它应该用g.seed(seed)
初始化,然后按所有(x,y)值的固定顺序调用,而不是每次都重新播种。这将有效地提供随机值,并具有预期的分布。
例如:
std::random_device rd;
std::mt19937 g{ rd() };
std::uniform_real_distribution<float> gen{ -1.0, 1.0 };
constexpr std::size_t nx = 100;
constexpr std::size_t nz = 100;
float noise[nx][nz];
void generateNoise() {
g.seed(seed);
for(int x = 0; x < nx; ++x) for(int x = 0; x < nx; ++x)
noise[x][z] = gen(g);
return gen(g);
}
答案 2 :(得分:2)
我不明白为什么你想要不断重播 - 这似乎毫无意义和缓慢。但那不是你要问的,所以......
rand
产生质量非常差的随机数。非常低的周期,通常基于线性同余发生器(不好)。而且,种子大小非常小。不要使用它 - <random>
存在是有原因的。
使用srand
进行播种的方式似乎很大程度上取决于您传入的x
和z
值,然后您乘以可能导致的大数字传递给srand
时溢出和截断,意味着(由于可能的种子值数量有限),您经常会重复使用相同的种子。
您可能想要访问的一些相关链接:
http://en.cppreference.com/w/cpp/numeric/random
https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful