Java Random(种子)在索引处获得Random?
下面的解释是我目前的代码Java Random(种子)在索引处获得Random?,java,random,Java,Random,下面的解释是我目前的代码 Random seeded = new Random(seed); for(int j = 0; j < 3; j++) { for (int i = 0; i < 10; i++) System.out.println(i + " : " + seeded.nextInt(100)); System.out.println("{}"); seeded= new Ran
Random seeded = new Random(seed);
for(int j = 0; j < 3; j++)
{
for (int i = 0; i < 10; i++)
System.out.println(i + " : " + seeded.nextInt(100));
System.out.println("{}");
seeded= new Random(seed);
}
我的目标正是上述目标。我想创建一个扩展Random的类,它包含一个GetSeedEdintaIndex函数。例如,我想实现这个类,如下所示
IndexedRandom random = new IndexedRandom(seed);
int iAt30 = random.getIntAtIndex(30);
目前,要做到这一点,我有以下代码
public int getIntAtIndex (int index)
{
Random temp = new Random(seed);
for(int i = 0; i < index - 1; i++)
temp.nextInt();
return temp.nextInt();
}
public int getIntAtIndex(int索引)
{
随机温度=新随机(种子);
对于(int i=0;i
我只是在随机X中循环多次,直到它达到所需的数量。然而,如果我选择一个大的索引,比如3000000,我更希望这个方法得到优化。有什么方法可以优化它吗?
这种方法在任何设备、PC或手机上运行只需约0.34秒。我问这个问题只是因为它看起来像是在浪费299999次计算,即使这对系统来说不是很难。如果可能的话,为什么不优化呢?简单的回答是:不,它是一个随机函数,生成的伪随机数是前一次执行的结果,因此它仅在以相同的方式应用时产生相同的结果 但是对于您的实现,还有一些替代方案。但在优化之前,您应该验证是否确实需要优化。因为我觉得这有点像过早优化。那么,为什么您希望优化此方法?您是否已经确定了要解决的性能瓶颈?多久调用一次?优化的权衡是什么?等等 因此,假设您有很好的理由对该方法进行优化,以下是一些备选方案:
- 根据内存限制,您可以预先填充一个完整的随机数数组并将其保存在内存中。这将需要约12 MB的内存。这可能是速度方面最有效的方法。如果经常只请求较低的值,您可以只预计算前1000个值并将其保存在内存中,然后计算高于此值的所有值。如果请求低于1000的值的频率高于请求更高的值的频率,则此方法是好的
- 如果您从未生成3M值,但3M仅定义值范围,另一种方法是将已计算的值保留在地图中,以便您可以查找它们,而不是重新计算它们。如果请求的索引相当随机,但对同一索引多次请求相同值的概率很高,那么这种方法将是好的
- 另一种方法是将以前的
实例保持为随机的
在地图中生成数字,然后从
随机数开始计算仅次于请求数字的索引。比如说
- getIntAtIndex(10)->索引<10不随机,计算10,
map.put(10,temp)
- getIntAtIndex(5)->索引<5不随机,计算为5,
map.put(5,temp)
- getIntAtIndex(7)->
,计算7,Random temp=map.remove(5)
map.put(7,temp)
- getIntAtIndex(12)->
,计算12,Random temp=map.remove(10)
map.put(12,temp)
- getIntAtIndex(10)->索引<10不随机,计算10,
Random
的实现是基于基本运算符的,因此编译器应该能够非常有效地进行优化。因此,在采取任何行动之前,我强烈建议分析是否真的存在瓶颈
编辑 我使用索引和迭代次数的各种组合运行测试。结果是,优化是你应该做的最低限度。我花了100秒来计算我5岁的核心搭档的指数100'000的值。执行时间随索引数线性增加,影响远大于预期 这使得上面列出的所有优化都完全过时了 假设用例是,您希望给定输入值的可复制伪随机值在每次程序执行时不同,但在运行时保持不变 因此,我建议采用不同的方法。使用索引值作为种子,并通过更改计算结果的迭代次数来添加随机数。下面的代码段将生成100个程序执行的随机序列。如果需要更多随机数,请更改计算“种子”的模,但要注意,执行时间以线性方式增加。所以也许100就足够了
private long seed = System.currentTimeMillis() % 100;
public int getIntAtIndex (int index)
{
Random temp = new Random(index);
for(int i = 0; i < seed; i++)
temp.nextInt();
return temp.nextInt();
}
private long seed=System.currentTimeMillis()%100;
公共整数getIntAtIndex(整数索引)
{
随机温度=新随机(索引);
for(int i=0;i
如果游戏是这样的,你应该用一个给定的种子初始化一个随机变量,然后通过重复使用同一个随机对象来计算游戏的“开始参数”来计算所有需要的值。也就是说,如果需要100个int参数,请调用100次nextInt()。
java.util.Random
是使用以下循环来推进种子:
(seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)
有两个原因使我没有尝试将其作为有效的Java语句编写。第一个是我们需要模幂运算来有效地计算它,第二个是我们需要80位算法来计算(a^N-1)mod(a-1)m
。这两个问题都可以使用Java来解决,Java提供和任意精度的整数。或者,我们可以使用模幂算法的一个变体来计算((a^N-1)mod(a-1)m)/(a-1)
作为(a^(N-1)+a^(N-2)+…+a+1)mod m
在64位算术的范围内,从而避免了我们必须经历biginger
的开销
Nayuki是我之前联系过的人之一,他有一个o
(seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)
new_seed = (a^N * seed mod m) + (b * ((a^N - 1) mod (a-1)m)/(a-1) mod m)