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

2ul0zpep  于 2023-04-19  发布在  Java
关注(0)|答案(7)|浏览(141)

我需要一个我正在创建的随机数生成器的帮助。我的代码如下(在一个名为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
这是强制性的,我设置的种子。
谢谢

vwhgwdsa

vwhgwdsa1#

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

public class Numbers {
    Random randnum;

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

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

vxbzzdmp2#

如果你总是设置种子,你将总是得到相同的答案。这就是设置种子所做的。

bnlyeluc

bnlyeluc3#

有两个问题导致了你所看到的。第一个是代码为Random示例设置了一个种子值。第二个是示例方法“random”示例化了一个新的Random对象,然后每次都立即用相同的种子设置它的种子。这两个的组合保证了,对于相同的i值,方法“random”将总是返回相同的值,并且它将总是种子总是生成的序列中的第一个。
假设设置种子是强制性的,为了每次都获得序列中的下一个值而不是序列中相同的第一个值,Random的randnum示例不能每次都在其下一个方法被调用之前设置其种子。要解决这个问题,请将Random的randnum局部变量示例从随机示例方法的作用域移动到类作用域。其次,仅当random被分配了一个Random示例时才设置seed,或者仅当从它获得相同的结果序列以重新开始时才设置seed。类Random的setSeed(long seed)示例方法不能在类作用域中执行,因此构造函数必须使用带有long seed参数的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的新示例是不必要的,也不浪费计算资源。
提供随机的种子参数,使得可以示例化产生可重复的序列的随机对象。无论何时使用该种子,下一个方法中的值序列都保证是相同的序列。这对于将要使用伪随机序列的测试软件很有用,其中结果必须是可预测的和可重复的。这对于在操作中创建不同的不可预测的伪随机序列是无用的。
语句“it is mandatory that I set the seed”否定了Random对象的伪随机序列的任何不可预测性。这是否适用于类项目或软件测试,其中对于程序的相同输入,结果必须相同?

o2g1uqev

o2g1uqev4#

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

klr1opcd

klr1opcd5#

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

l7wslrjt

l7wslrjt6#

你一定要在你的random(int i)方法中创建new Random()吗?如果你有义务这样做,你可以使用,你可以将种子设置为当前时间,尽管这不是防失败的,因为你可以在另一个numbers.random(10)之后快速调用它,结果它将成为同一个种子。(System.nanoTime()我想?如果setSeed只接受int,我想乘它)。
但是,如果允许的话,我的建议是在你的方法外面声明Random**。如果你在number类构造函数中示例化你的随机变量,你可以设置任何种子,每当你调用你的方法时,它都会给予你一个新的数字。(如果使用常量种子,每次重新启动应用程序时,它们都是相同的数字集,但是,在这种情况下,也可以使用时间作为种子)。
最后,最后一个问题可能是如果你同时声明了几个number类。它们都有相同的随机种子,并给予你相同的随机数集。如果发生这种情况,你可以在你的主类中创建一个static Random,并在你的numbers类中调用它。这将耦合这两个类。另一种选择是为每个示例化的number发送一个递增值到number类构造函数,并使用传递的值作为种子。
第二个选择应该对你有好处,如果你被允许这样做的话。

u7up0aaq

u7up0aaq7#

通常,Random不是真正的随机,而是伪随机
这意味着它需要一个给定的种子,并使用它来生成一个看起来像随机的数字序列(但是可预测的并且如果你放入相同的种子它会重复)。
如果你不放种子,那么第一个种子将从一个可变的源(通常是系统时间,单位是纳米)。
通常,将使用具有种子的值,以便使其重复精确的伪随机生成的值(例如,用于测试)。
建议的解决方案:

  • 使用不带种子的Random()
  • 在你的类的构造器中用一个种子启动Random(long seed)一次,然后在你需要得到一个伪随机数的时候调用nextInt

相关问题