2011-04-03 101 views
16

我需要使用我创建的随机数生成器的帮助。我的代码如下:(一类叫号内):当我设置种子时,Java随机总是返回相同的数字?

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

我必须设置种子。

感谢

+3

每次调用函数时都不要创建新的Random对象。将其保存为私有变量并仅实例化一次 – Rob 2011-04-03 23:21:57

+0

将种子设置为什么? – 2011-04-03 23:22:23

+0

不建议手动设置种子,除非您确切知道它的含义。 – m0skit0 2015-03-15 22:41:11

回答

36

你需要在整个类共享Random()实例:

public class Numbers { 
    Random randnum; 

    public Numbers() { 
     randnum = new Random(); 
     randnum.setSeed(123456789); 
    } 

    public int random(int i){ 
     return randnum.nextInt(i); 
    } 
} 
32

如果你总是设置种子,你总是会得到相同的答案。这就是设定种子的原因。

3

在启动时设置种子一次,而不是每次你想要一个新的随机数。

2

你正在使用的不是一个随机数发生器,它是一个伪随机数发生器。 PRNG生成伪随机数序列,种子选择序列中的起始点(PRNG可以生成一个或多个序列)。

1

通常,随机并不是真正的随机而是伪随机。这意味着它需要一个给定的种子,并用它来产生一个看起来像随机的数字序列(但它是可预测的,如果放入相同的种子,它会重复)。

如果你不把种子,那么第一个种子会从可变电源(通常是系统时间)拍摄。

通常,与种子的值将被使用以便它具有重复的准确值(例如,用于测试)。改为使用无种子代替。

2

你一定需要创建random(int i)方法里面new Random()?如果你有义务这样做,你可以使用,你可以将种子设置为当前时间,尽管这不是失败的证据,因为你可以在另一个之后如此快速地调用你的种子,以至于最终会变成相同的种子。你可以尝试使用nanoSeconds(System.nanoTime()我认为?如果setSeed只接受int,那么我猜)。

但是我会建议,但是,如果你被允许这样做,就是声明你的随机你的方法。如果你使用你的随机变量,例如你的类构造函数,你可以设置任何种子,每当你调用你的方法时,它会给你一个新的数字。 (如果您使用恒定的种子,每次重新启动应用程序时,它们将会是相同的数字组,但是在这种情况下,您也可以使用时间作为种子)。

最后,如果你在同一时间宣布几个number类的最后一个问题可能是。他们将拥有相同的随机种子,并给你相同的一组随机数。如果发生这种情况,您可以在您的主课堂中制作一个static Random,并在您的电话号码类中调用它。这虽然会将这两个班级结合起来,但它会起作用。另一种选择是将递增值发送给您的类构造函数,对于每个number您实例化,并使用您传递的值作为种子。

第二个选择应该是对你有好处,不过,如果你被允许这样做的。

12

有造成你所看到的两个问题。第一个是代码为Random实例设置种子值。第二个是实例方法“随机”实例一个新的Random对象,然后每次立即使用相同的种子设置其种子。这两个组合确保了对于i的相同值,“随机”方法将始终返回相同的值,并且它始终是种子始终生成的序列中的第一个。

假设设置种子是强制性的,为了获得序列中的下一个值而不是每次序列的相同第一个值,Random的randnum实例不能每次都在其下一个方法之前设置其种子被调用。要解决这个问题,请将随机实例方法范围内的Random的randnum局部变量实例移至类作用域。其次,只有在随机分配了一个随机实例或者只是为了从中得到相同的结果序列以重新开始时才设置种子。 Class 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(long seed) 

和实例方法

setSeed(long seed) 

所有影响从随机实例获得的数字序列。实例方法

setSeed(long seed) 

将Random对象设置为与原构造函数实参相同的种子只会实例化的相同状态。只有一个种子值的低阶48位被使用。

如果随机对象没有实例化种子,种子将是相同的以毫秒为单位的系统时间。这确保了,除非两个Random对象在同一毫秒内实例化,否则它们将产生不同的伪随机序列。只有种子值的低位48位被使用。这导致不可预知的伪随机序列。每次调用下一个方法时,都不需要浪费计算资源来获取Random的新实例。

随机

的种子参数被提供,使得一个可能实例,其产生的序列是可重复的随机对象。对于给定的种子,无论何时使用种子,下一种方法中的值序列都保证是相同的序列。这对测试将使用伪随机序列的软件非常有用,因为结果必须是可预测和可重复的。它在操作中创建不同的不可预测的伪随机序列是没有用的。

声明“我强制设置种子”否定任何Random对象的伪随机序列的不可预测性。这是用于课程项目还是软件测试,结果必须与程序的相同输入相同?