- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
为了提供一些背景信息,我一直在用 Java 编写一个基本的 Perlin 噪声实现,在实现播种时,我遇到了一个我无法解释的错误。
为了无论查询哪组坐标的噪声水平以及以什么顺序每次都为同一个种子生成相同的随机权重 vector ,我生成了一个新种子(newSeed
),基于原始种子和权重 vector 坐标的组合,并通过运行将其作为权重 vector 随机化的种子:
rnd.setSeed(newSeed);
weight = new NVector(2);
weight.setElement(0, rnd.nextDouble() * 2 - 1);
weight.setElement(1, rnd.nextDouble() * 2 - 1);
weight.normalize()
其中NVector
是一个自制的 vector 数学类。
但是,在运行时,程序会产生非常糟糕的噪音:
经过一番挖掘,我发现每个 vector 的第一个元素非常相似(因此每个 setSeed()
调用之后的第一个 nextDouble()
调用)导致在 vector 网格中每个 vector 的第一个元素是相似的。
这可以通过运行来证明:
long seed = Long.valueOf(args[0]);
int loops = Integer.valueOf(args[1]);
double avgFirst = 0.0, avgSecond = 0.0, avgThird = 0.0;
double lastfirst = 0.0, lastSecond = 0.0, lastThird = 0.0;
for(int i = 0; i<loops; i++)
{
ran.setSeed(seed + i);
double first = ran.nextDouble();
double second = ran.nextDouble();
double third = ran.nextDouble();
avgFirst += Math.abs(first - lastfirst);
avgSecond += Math.abs(second - lastSecond);
avgThird += Math.abs(third - lastThird);
lastfirst = first;
lastSecond = second;
lastThird = third;
}
System.out.println("Average first difference.: " + avgFirst/loops);
System.out.println("Average second Difference: " + avgSecond/loops);
System.out.println("Average third Difference.: " + avgSecond/loops);
在程序参数指定的一系列种子上调用 setSeed()
方法后生成的第一个、第二个和第三个随机数之间的平均差异;对我来说返回了这些结果:
C:\java Test 462454356345 10000
Average first difference.: 7.44638117976783E-4
Average second Difference: 0.34131692827329957
Average third Difference.: 0.34131692827329957
C:\java Test 46245445 10000
Average first difference.: 0.0017196011123287126
Average second Difference: 0.3416750057190849
Average third Difference.: 0.3416750057190849
C:\java Test 1 10000
Average first difference.: 0.0021601598225344998
Average second Difference: 0.3409914232342002
Average third Difference.: 0.3409914232342002
在这里您可以看到第一个平均差异明显小于其他平均差异,并且似乎随着种子的增加而减小。
因此,通过在设置权重 vector 之前向 nextDouble()
添加一个简单的虚拟调用,我能够修复我的 perlin 噪声实现:
rnd.setSeed(newSeed);
rnd.nextDouble();
weight.setElement(0, rnd.nextDouble() * 2 - 1);
weight.setElement(1, rnd.nextDouble() * 2 - 1);
导致:
我想知道为什么在第一次调用 nextDouble()
时会出现这种糟糕的变化(我没有检查其他类型的随机性)和/或提醒人们注意这个问题。
当然,这可能只是代表我的一个实现错误,如果有人向我指出,我将非常感激。
最佳答案
Random
类被设计为伪随机数的低开销源。但是“低开销”实现的结果是数字流具有远非完美的属性......从统计角度来看。您遇到了其中一种缺陷。 Random
被记录为线性同余生成器,并且此类生成器的属性众所周知。
有多种方法可以解决此问题。例如,如果你小心,你可以隐藏一些最明显的“差”特征。 (但建议您进行一些统计测试。您看不到添加到第二张图像的噪声的非随机性,但它仍然可能存在。)
或者,如果您想要保证良好统计特性的伪随机数,那么您应该使用 SecureRandom
而不是 Random
。它的开销显着增加,但您可以放心,许多“聪明人”会花费大量时间在算法的设计、测试和分析上。
最后,创建一个 Random
的子类相对简单,该子类使用另一种算法生成数字;见 link .问题是您必须选择(或设计)并实现适当的算法。
将此称为“问题”值得商榷。这是 LCG 的众所周知和理解的特性,使用 LCG 是一种有意识的工程选择。人们想要低开销的 PRNG,但低开销的 PRNG 的属性很差。坦斯塔夫。
当然,Oracle 不会考虑在 Random
中进行更改。确实,不改变的原因在javadoc 中有明确说明。对于 Random
类。
"In order to guarantee this property, particular algorithms are specified for the class
Random
. Java implementations must use all the algorithms shown here for the classRandom
, for the sake of absolute portability of Java code."
关于java - Java中setSeed之后的第一个随机数总是相似的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27760450/
我遇到了一个概念上的小问题。 我需要播种随机数,以便在重新加载关卡时始终获得相同的随机数。 因此我需要使用 Random#setSeed . 我遇到的问题是我需要做一个 Random r = new
我有一个名为“Face”的类,它创建 java.util.Random 的静态实例: public static Random random = new Random(); 然后,在 Main 中,我
为什么这会在每一列中返回不同的随机数?我认为如果我使用 setseed(),我将始终获得相同的随机数。但看起来每次调用 random() 时都有新的随机数常量向量。 SQLFiddle select
编写Java程序时,我们使用setSeed在 Random 类中。我们为什么要使用这种方法? 我们不能只使用 Random 而不使用 setSeed 吗?使用 setSeed 的主要目的是什么? 最佳
我编写了以下程序在我的 java 卡中生成一个 16 字节 随机数。我使用 apdu 缓冲区作为种子: public class RandomNumber extends Applet { p
运行 macOS High Sierra 10.13.5 和 Java 1.8.0u171。 我有类似以下代码: SecureRandom random = SecureRandom.getInsta
我想生成用于 RSA key 生成的两个素数。我认为为了增加两个素数的随机性,可以按如下方式生成随机数: SecureRandom r = SecureRandom.getInstance("SHA1
参见 http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#setSeed(long) .代码 xors 种子与乘数减少它 mo
我有一个带有属性的电影数据库。我想以随机顺序将这些电影的查询批处理返回到带有分页的模板。我正在使用 will_paginate。我尝试了以下方法: ## MoviesController movies
我是一名优秀的程序员,十分优秀!