当我设置种子时,Java随机总是返回相同的数字?

Java random always returns the same number when I set the seed?

我需要我正在创建的随机数生成器的帮助。我的代码如下(在名为数字的类中):

1
2
3
4
5
public int random(int i){
    Random randnum = new Random();
    randnum.setSeed(123456789);
    return randnum.nextInt(i);
}

当我从另一个类调用这个方法(为了生成一个随机数)时,它总是返回相同的数字。例如,如果我要这样做:

1
2
System.out.println(numbers.random(10));
System.out.print(numbers.random(10));

它总是打印相同的数字,例如5 5。我该怎么做才能打印出两个不同的数字,例如5-8

我必须播种。

谢谢


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

1
2
3
4
5
6
7
8
9
10
11
12
public class Numbers {
    Random randnum;

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

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

如果你总是设定种子,你总会得到同样的答案。这就是播种的作用。


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

假设设置种子是必需的,为了每次获取序列中的下一个值而不是序列中的同一个第一个值,RandNum实例不能在每次调用其下一个方法之前设置其种子。要解决这个问题,请将RandNum局部变量实例从Random实例方法的作用域移动到类作用域。第二,仅当随机实例被分配时设置种子,或者仅从中获得相同的结果序列,以便重新开始。类random的set seed(long seed)实例方法不能在类范围内执行,因此构造函数必须使用带有long seed参数的随机构造函数进行设置。以下代码显示了更改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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有两个构造函数:

1
Random(long seed)

一个实例方法

1
setSeed(long seed)

所有这些都会影响从随机实例中获得的数字序列。实例方法,

1
setSeed(long seed)

将随机对象设置为与构造函数参数具有相同种子的实例所处的状态。仅使用种子值的低阶48位。

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

提供了Random的种子参数,以便可以实例一个随机对象,该对象生成一个可重复的序列。对于给定的种子,无论何时使用该种子,下一个方法中的值序列都保证是相同的序列。这对于测试将要使用伪随机序列的软件很有用,在这些伪随机序列中,结果必须是可预测和可重复的。它对于在操作中创建不同的不可预测的伪随机序列没有用处。

语句"我必须设置种子"否定了随机对象伪随机序列的任何不可预测性。对于一个类项目或软件测试来说,对于程序的相同输入,结果必须相同吗?


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


您是否需要在您的random(int i)方法中创建new Random()?如果你必须这样做,你可以使用,你可以设置种子到目前的时间,虽然这不是失败的证明,因为你可以调用你的numbers.random(10),如此之快的一个接一个,它将最终成为相同的种子。你可以尝试使用纳秒(system.nanome()我想?如果setseed只接受int,我想应该乘以它)。

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

最后,最后一个问题可能是,如果您同时声明几个number类。它们都会有相同的随机种子,并给你相同的随机数。如果发生这种情况,您可以在主类中生成一个static Random,并在数字类中调用它。不过,这将使这两个类结合起来,但它会起作用。另一种选择是为您声明的每个number类构造函数发送一个递增的值,并使用您传递的值作为种子。

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


您使用的不是随机数生成器,而是伪随机数生成器。prng生成伪随机数序列,种子选择序列中的起始点(prng可以生成一个或多个序列)。


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

如果不输入种子,那么第一个种子将从变量源(通常是系统时间)中获取。

通常,会使用带有种子的值,以便使其重复精确的值(例如,用于测试)。用无种子的随机数代替。