我需要帮助我正在创建的随机数生成器。我的代码如下(在一个名为numbers的类中):
public int random(int i){
Random randnum = new Random();
randnum.setSeed(123456789);
return randnum.nextInt(i);
}
当我从另一个类调用此方法时(为了生成一个随机数),它总是返回相同的数字。例如,如果我这样做:
System.out.println(numbers.random(10));
System.out.print(numbers.random(10));
它始终打印相同的数字,例如5 5.我必须做什么才能打印两个不同的数字,例如5 8
我必须设置种子。
由于
答案 0 :(得分:44)
您需要在整个班级中共享Random()
个实例:
public class Numbers {
Random randnum;
public Numbers() {
randnum = new Random();
randnum.setSeed(123456789);
}
public int random(int i){
return randnum.nextInt(i);
}
}
答案 1 :(得分:35)
如果您始终设置种子,您将始终得到相同的答案。这就是设置种子的原因。
答案 2 :(得分:14)
导致您看到的内容有两个问题。第一个是代码为Random实例设置种子值。第二个是实例方法“random”实例化一个新的Random对象,然后每次立即使用相同的种子设置其种子。这两者的组合保证,对于i的相同值,方法“random”将始终返回相同的值,并且它将始终是种子始终生成的序列中的第一个。
假设设置种子是必需的,为了获得序列中的下一个值而不是每次都获得序列的相同第一个值,Random的randnum实例每次在其下一个方法获得之前都不能设置其种子集调用。要解决此问题,请将Random的randnum局部变量实例从随机实例方法的范围移动到类范围。其次,仅在为随机分配一个Random实例时设置种子,或者仅为了从中获取相同的结果序列以重新开始。 Random Random的setSeed(long seed)实例方法无法在类范围内执行,因此构造函数必须使用带有long种子参数的Random构造函数来设置它。以下代码显示了更改:
public class RandomDemo { // arbitrary example class name
// lots of class related stuff may be here...
// still inside the class scope...
// private is a good idea unless an external method needs to change it
private Random randnum = new Random(123456789L);
// the seed guarantees it will always produce the same sequence
// of pseudo-random values when the next methods get called
// for unpredicable sequences, use the following constructor instead:
// private Random randnum = new Random();
// lots of code may be here...
// publicly exposed instance method for getting random number
// from a sequence determined by seed 123456789L
// in the range from 0 through i-1
public int randnum(int i) {
// don't set the seed in here, or randnum will return the exact same integer
// for the same value of i on every method call
// nextInt(i) will give the next value from randnum conforming to range i
return randnum.nextInt(i);
} // end randnum
// lots of more code may be here...
} // end class RandDemo
如上所述,上述内容将为您提供准确解决问题的方法。然而,鉴于它的作用,使用强制种子似乎是不寻常的。
如果这是针对序列必须可预测且可重复的类项目或软件测试,则将种子设置为固定值是有意义的。否则,质疑将种子设置为某个预定值的有效性。以下解释更多关于随机种子,随机种子以及为何提供种子的规定。
Random有两个构造函数:
Random()
和
Random(long seed)
和实例方法
setSeed(long seed)
这些都会影响从Random实例获得的数字序列。实例方法
setSeed(long seed)
将Random对象设置为与使用与构造函数参数相同的种子实例化时所处的状态相同。仅使用种子值的低48位。
如果在没有种子的情况下实例化Random对象,则种子将与系统时间相同(以毫秒为单位)。这确保了,除非两个Random对象在相同的毫秒内实例化,否则它们将产生不同的伪随机序列。仅使用种子值的低48位。这导致不可预测的伪随机序列。每次调用下一个方法时,都不需要浪费计算资源来获取Random的新实例。
提供Random的种子参数,以便可以实例化一个产生可重复序列的Random对象。对于给定的种子,无论何时使用该种子,下一种方法中的值序列都保证是相同的序列。这对于测试将使用伪随机序列的软件非常有用,其中结果必须是可预测且可重复的。在操作中创建不同的不可预测的伪随机序列是没有用的。
声明“我必须设置种子”否定了Random对象的伪随机序列的任何不可预测性。这是针对类项目还是软件测试,对于程序的相同输入,结果必须相同?
答案 3 :(得分:3)
在启动时设置一次种子,而不是每次需要一个新的随机数。
答案 4 :(得分:2)
您使用的不是随机数生成器,它是伪随机数生成器。 PRNG生成伪随机数序列,种子选择序列中的起始点(PRNG可以生成一个或多个序列)。
答案 5 :(得分:2)
您是否一定需要在new Random()
方法中创建random(int i)
?如果你有责任这样做,你可以使用,你可以将种子设置为当前时间,虽然这不是故障证明,因为你可以在另一个之后如此快地调用你的numbers.random(10)
它会结束成为同一个种子。您可以尝试使用nanoSeconds(我认为System.nanoTime()?如果setSeed只接受int,我猜它会相乘)。
但我建议,如果您被允许这样做,则声明您的方法是随机外部。如果你在你的number
类构造函数中实例化你的随机变量,你可以设置任何种子,只要你调用你的方法,它就会给你一个新的数字。 (如果使用常量种子,每次重新启动应用程序时它们将是相同的数字组,但是,在这种情况下,您也可以使用时间作为种子)。
最后,如果您同时声明多个number
类,最后一个问题可能就是。它们都将具有相同的随机种子,并为您提供相同的随机数。如果发生这种情况,您可以在主课程中设置static Random
,并在您的数字课程中调用它。这将结合这两个类,但它会工作。另一种选择是向您的number
类构造函数发送递增值,对于您实例化的每个number
,并使用您传递的值作为种子。
第二种选择应该对你有好处,如果你被允许这样做的话。
答案 6 :(得分:1)
通常,Random不是真正的随机而是伪随机。这意味着它需要一个给定的种子,并使用它来生成一系列看起来像随机的数字(但是可以预测,如果你把相同的种子重复,它会重复)。
如果你没有放种子,那么第一粒种子将从可变来源(通常是系统时间)中取出。
通常,将使用带种子的值,以使其重复精确值(例如,用于测试)。使用Random而不使用种子。