Java的Random值每次都不同

时间:2010-05-12 07:42:37

标签: java random

我希望Random每次都返回相同的值。所以我尝试给它一个常数种子。但它仍然会返回随机值。我怎么能阻止这个?

编辑:我在我的代码中使用相同的Random对象,第一次测试我的程序时,我从随机中得到以下值:

13, 9, 10, 12, 14, 11, 15, 10, 8, 6, 12, 9, 7, 7, 6, 1, 0, 0, 0, 80, 33, 3, 0, 45, 6, 2, 51, 50, 3, 0, 1, 1, 0, 2, 3, 0, 0, 2, 0, 3, 0, 1, 33, 1, 22, 7, 55, 92, 33, 1, 5, 6, 10, 2, 1, 85, 26, 1, 3, 42, 16, 0, 2, 34, 0, 1, 2, 8, 0, 73, 1, 4, 66, 59, 49, 99, 2, 4, 97, 57, 85, 28, 0, 2, 3, 9, 36, 1, 19, 4, 0, 71, 9, 2, 3, 76, 6, 3, 0, 96, 84, 22, 0, 0, 1, 1, 0, 1, 0, 0, 2, 0, 0, 0, 0, 58, 2, 1, 2, 1, 0, 1, 5, 0, 0, 1, 0, 4, 21, 59, 3, 1, 6, 3, 6, 0, 0, 3, 2, 2, 3, 5, 3, 0, 6, 5, 60, 3, 4, 4, 2, 6, 1, 3, 5, 1, 5, 26, 4, 0, 25, 5, 0, 61, 2, 0, 29, 2, 1, 34, 57, 55, 61, 1, 1, 21, 6, 1, 3, 0, 56, 6, 23, 6, 0, 47, 1, 1, 55, 0, 0, 5, 1, 4, 0, 57, 21, 45, 2, 0, 3, 0, 6, 1, 64, 39, 2, 0, 51, 31, 13, 9, 10, 12, 14, 11, 15, 10, 8, 6, 12, 9, 7, 7, 6, 1, 0, 0, 0, 80, 33, 3, 0, 45, 6, 2, 51, 50, 3, 0, 1, 1, 0, 2, 3, 0, 0, 2, 0, 3, 0, 1, 33, 1, 22, 7, 55, 92, 33, 1, 5, 6, 10, 2, 1, 85, 26, 1, 3, 42, 16, 0, 2, 34, 0, 1, 2, 8, 0, 73, 1, 4, 66, 59, 49, 99, 2, 4, 97, 57, 85, 28, 0, 2, 3, 9, 36, 1, 19, 4, 0, 71, 9, 2, 3, 76, 6, 3, 0, 96, 84, 22, 0, 0, 1, 1, 0, 1, 0, 0, 2, 0, 0, 0, 0, 58, 2, 1, 2, 1, 0, 1, 5, 0, 0, 1, 0, 4, 21, 59, 3, 1, 6, 3, 6, 0, 0, 3, 2, 2, 3, 5, 3, 0, 6, 5, 60, 3, 4, 4, 2, 6, 1, 3, 5, 1, 5, 26, 4, 0, 25, 5, 0, 61, 2, 0, 29, 2, 1, 34, 57, 55, 61, 1, 1, 21, 6, 1, 3, 0, 56, 6, 23, 6, 0, 47, 1, 1, 55, 0, 0, 5, 1, 4, 0, 57, 21, 45, 2, 0, 3, 0, 6, 1, 64, 39, 2, 0, 51, 31

我第二次得到:

13, 9, 10, 12, 14, 11, 15, 10, 8, 6, 12, 9, 7, 7, 6, 1, 0, 0, 0, 2, 1, 1, 3, 1, 0, 33, 9, 61, 1, 2, 54, 59, 99, 28, 0, 88, 11, 0, 0, 92, 24, 0, 47, 43, 83, 13, 1, 1, 53, 46, 22, 0, 2, 0, 0, 0, 0, 2, 0, 13, 8, 1, 16, 6, 2, 34, 0, 1, 2, 8, 0, 73, 1, 4, 66, 59, 49, 99, 2, 0, 97, 57, 85, 28, 5, 2, 3, 3, 36, 4, 19, 0, 0, 71, 9, 2, 3, 76, 6, 0, 0, 0, 2, 4, 2, 0, 1, 0, 1, 1, 0, 0, 0, 2, 6, 1, 58, 2, 1, 2, 1, 0, 1, 5, 0, 0, 0, 0, 4, 21, 59, 3, 1, 6, 3, 6, 0, 0, 3, 2, 2, 3, 5, 3, 0, 6, 5, 60, 3, 4, 4, 2, 6, 1, 3, 5, 1, 5, 26, 4, 0, 25, 5, 0, 61, 2, 0, 29, 2, 1, 34, 57, 55, 61, 1, 1, 21, 6, 1, 3, 0, 56, 6, 23, 6, 0, 47, 1, 1, 55, 0, 0, 5, 1, 4, 0, 57, 21, 45, 2, 0, 13, 9, 10, 12, 14, 11, 15, 10, 8, 6, 12, 9, 7, 7, 6, 1, 0, 0, 0, 2, 1, 1, 3, 1, 0, 33, 9, 61, 1, 2, 54, 59, 99, 28, 0, 88, 11, 0, 0, 92, 24, 0, 47, 43, 83, 13, 1, 1, 53, 46, 22, 0, 2, 0, 0, 0, 0, 2, 0, 13, 8, 1, 16, 6, 2, 34, 0, 1, 2, 8, 0, 73, 1, 4, 66, 59, 49, 99, 2, 0, 97, 57, 85, 28, 5, 2, 3, 3, 36, 4, 19, 0, 0, 71, 9, 2, 3, 76, 6, 0, 0, 0, 2, 4, 2, 0, 1, 0, 1, 1, 0, 0, 0, 2, 6, 1, 58, 2, 1, 2, 1, 0, 1, 5, 0, 0, 0, 0, 4, 21, 59, 3, 1, 6, 3, 6, 0, 0, 3, 2, 2, 3, 5, 3, 0, 6, 5, 60, 3, 4, 4, 2, 6, 1, 3, 5, 1, 5, 26, 4, 0, 25, 5, 0, 61, 2, 0, 29, 2, 1, 34, 57, 55, 61, 1, 1, 21, 6, 1, 3, 0, 56, 6, 23, 6, 0, 47, 1, 1, 55, 0, 0, 5, 1, 4, 0, 57, 21, 45, 2, 0

前几个值非常相似,但其余的。好吧,你可以看到

我使用私有静态随机r =新随机(SEED); //在此之后,种子永远不会改变 我也使用这个随机的随机化字节数组。问题是,我为相同的输入获得了不同的输出。我希望我可以发布更多代码,但这是一个非常大的项目发布在这里。

7 个答案:

答案 0 :(得分:6)

我只能看到两种可能发生这种情况的方式:

  1. 这两次执行并不完全相同的调用顺序。有一些你想念的东西 - 例如从一些其他线程或其他东西对随机对象进行一些方法调用。由于PRNG是完全确定的,这是最可能的事情 - 我相信你已经检查了它,但它似乎仍然是最可能的解释。

  2. 您在PRNG中发现了一个错误。不太可能但并非不可能 - 如果您向我们提供Java版本,种子使用等详细信息,那么我们可以尝试重现它。

  3. 在任何情况下,我强烈建议您创建一个“尽可能短”的玩具应用程序,它可以复制差异,然后在问题仍然存在时用它更新您的问题

答案 1 :(得分:4)

以下代码片段应始终生成相同的输出:

import java.util.Random;
public class Test {
    public static void main(String... args) {
        Random r = new Random(123456L);     // use the seed 123456L
        System.out.println(r.nextInt(10));
        System.out.println(r.nextInt(10));
        System.out.println(r.nextInt(10));
        System.out.println(r.nextInt(10));
    }
}

<强>输出:

3
7
7
5

要回到“真正的”随机行为,只需删除构造函数的参数(它将选择一个“随机”种子)。


有关详细信息,请参阅API-docs for Random

  

Random

     

public Random(long seed)

     
使用单个长种子创建新的随机数生成器。种子是伪随机数发生器的内部状态的初始值,它由方法next(int)维持。

        调用new Random(seed)相当于:

Random rnd = new Random();
rnd.setSeed(seed);
     
     

参数:
         seed - 初始种子
     另见:
         setSeed(long)


如果您希望r.nextInt(10)每次电话都返回相同的号码,则需要执行以下操作:

        r.setSeed(123456L);
        System.out.println(r.nextInt(10));
        r.setSeed(123456L);
        System.out.println(r.nextInt(10));
        r.setSeed(123456L);
        System.out.println(r.nextInt(10));
        r.setSeed(123456L);
        System.out.println(r.nextInt(10));

答案 2 :(得分:2)

您是否使用java.util.Random类或java.lang.Math.random()的实例?

根据随机的javadoc:

  

如果使用相同的种子创建了两个Random实例,并且为每个实例创建了相同的方法调用序列,则它们将生成并返回相同的数字序列。

答案 3 :(得分:1)

你的两个序列远非随机的整数序列。存在大量重复,并且子序列的大部分彼此相等。我相信你的代码中有一些错误。

序列1:

13, 9, 10, 12, 14, 11, 15, 10, 8, 6, 12, 9, 7, 7, 6, 1, 0, 0, 0,

80, 33, 3, 0, 45, 6, 2, 51, 50, 3, 0, 1, 1, 0, 2, 3, 0, 0, 2, 0, 3, 0, 1, 33, 1, 22, 7, 55, 92, 33, 1, 5, 6, 10, 2, 1, 85, 26, 1, 3, 42, 16, 0,

2, 34, 0, 1, 2, 8, 0, 73, 1, 4, 66, 59, 49, 99, 2, 4, 97, 57, 85, 28, 0, 2, 3, 9, 36, 1, 19, 4, 0, 71, 9, 2, 3, 76, 6, 3, 0, 96, 84, 22, 0, 0, 1, 1, 0, 1, 0, 0, 2, 0, 0, 0, 0, 58, 2, 1, 2, 1, 0, 1, 5, 0, 0, 1, 0, 4, 21, 59, 3, 1, 6, 3, 6, 0, 0, 3, 2, 2, 3, 5, 3, 0, 6, 5, 60, 3, 4, 4, 2, 6, 1, 3, 5, 1, 5, 26, 4, 0, 25, 5, 0, 61, 2, 0, 29, 2, 1, 34, 57, 55, 61, 1, 1, 21, 6, 1, 3, 0, 56, 6, 23, 6, 0, 47, 1, 1, 55, 0, 0, 5, 1, 4, 0, 57, 21, 45, 2, 0, 3, 0, 6, 1, 64, 39, 2, 0, 51, 31,

13, 9, 10, 12, 14, 11, 15, 10, 8, 6, 12, 9, 7, 7, 6, 1, 0, 0, 0,

80, 33, 3, 0, 45, 6, 2, 51, 50, 3, 0, 1, 1, 0, 2, 3, 0, 0, 2, 0, 3, 0, 1, 33, 1, 22, 7, 55, 92, 33, 1, 5, 6, 10, 2, 1, 85, 26, 1, 3, 42, 16, 0,

2, 34, 0, 1, 2, 8, 0, 73, 1, 4, 66, 59, 49, 99, 2, 4, 97, 57, 85, 28, 0, 2, 3, 9, 36, 1, 19, 4, 0, 71, 9, 2, 3, 76, 6, 3, 0, 96, 84, 22, 0, 0, 1, 1, 0, 1, 0, 0, 2, 0, 0, 0, 0, 58, 2, 1, 2, 1, 0, 1, 5, 0, 0, 1, 0, 4, 21, 59, 3, 1, 6, 3, 6, 0, 0, 3, 2, 2, 3, 5, 3, 0, 6, 5, 60, 3, 4, 4, 2, 6, 1, 3, 5, 1, 5, 26, 4, 0, 25, 5, 0, 61, 2, 0, 29, 2, 1, 34, 57, 55, 61, 1, 1, 21, 6, 1, 3, 0, 56, 6, 23, 6, 0, 47, 1, 1, 55, 0, 0, 5, 1, 4, 0, 57, 21, 45, 2, 0, 3, 0, 6, 1, 64, 39, 2, 0, 51, 31

序列2:

// In sync with sequence 1
13, 9, 10, 12, 14, 11, 15, 10, 8, 6, 12, 9, 7, 7, 6, 1, 0, 0, 0,

// Out of sync with sequence 1
2, 1, 1, 3, 1, 0, 33, 9, 61, 1, 2, 54, 59, 99, 28, 0, 88, 11, 0, 0, 92, 24, 0, 47, 43, 83, 13, 1, 1, 53, 46, 22, 0, 2, 0, 0, 0, 0, 2, 0, 13, 8, 1, 16, 6,

// Back in sync!
2, 34, 0, 1, 2, 8, 0, 73, 1, 4, 66, 59, 49, 99, 2, 0, 97, 57, 85, 28, 5, 2, 3, 3, 36, 4, 19, 0, 0, 71, 9, 2, 3, 76, 6, 0, 0, 0, 2, 4, 2, 0, 1, 0, 1, 1, 0, 0, 0, 2, 6, 1, 58, 2, 1, 2, 1, 0, 1, 5, 0, 0, 0, 0, 4, 21, 59, 3, 1, 6, 3, 6, 0, 0, 3, 2, 2, 3, 5, 3, 0, 6, 5, 60, 3, 4, 4, 2, 6, 1, 3, 5, 1, 5, 26, 4, 0, 25, 5, 0, 61, 2, 0, 29, 2, 1, 34, 57, 55, 61, 1, 1, 21, 6, 1, 3, 0, 56, 6, 23, 6, 0, 47, 1, 1, 55, 0, 0, 5, 1, 4, 0, 57, 21, 45, 2, 0,

13, 9, 10, 12, 14, 11, 15, 10, 8, 6, 12, 9, 7, 7, 6, 1, 0, 0, 0,

// Out of sync again...
2, 1, 1, 3, 1, 0, 33, 9, 61, 1, 2, 54, 59, 99, 28, 0, 88, 11, 0, 0, 92, 24, 0, 47, 43, 83, 13, 1, 1, 53, 46, 22, 0, 2, 0, 0, 0, 0, 2, 0, 13, 8, 1, 16, 6,

// Back in sync....
2, 34, 0, 1, 2, 8, 0, 73, 1, 4, 66, 59, 49, 99, 2, 0, 97, 57, 85, 28, 5, 2, 3, 3, 36, 4, 19, 0, 0, 71, 9, 2, 3, 76, 6, 0, 0, 0, 2, 4, 2, 0, 1, 0, 1, 1, 0, 0, 0, 2, 6, 1, 58, 2, 1, 2, 1, 0, 1, 5, 0, 0, 0, 0, 4, 21, 59, 3, 1, 6, 3, 6, 0, 0, 3, 2, 2, 3, 5, 3, 0, 6, 5, 60, 3, 4, 4, 2, 6, 1, 3, 5, 1, 5, 26, 4, 0, 25, 5, 0, 61, 2, 0, 29, 2, 1, 34, 57, 55, 61, 1, 1, 21, 6, 1, 3, 0, 56, 6, 23, 6, 0, 47, 1, 1, 55, 0, 0, 5, 1, 4, 0, 57, 21, 45, 2, 0

答案 4 :(得分:0)

使用相同的种子应该在每个平台上产生相同的确切序列。

请记住,如果您使用相同的Random对象除了nextInt调用之外还执行nextBoolean或nextBytes调用,并且它们不会与nextInt调用一起出现在同一个确切的序列中,这会影响你在nextInt电话中得到的序列。此外,每次调用next时,每次都必须在相同的序列中使用相同的参数值或无参数,以使返回相同。

对Random对象的每次下一次调用都会影响序列。换句话说,即使您使用种子,nextInt,nextBoolean和nextBytes也会相互影响并影响序列。要获得完全可重复的结果,您必须使用具有相同下一次调用序列的相同种子。

以下是两对结果。第一对是从0到99之间生成100个整数,然后创建一个具有相同种子的新Random,并生成0到99之间的另外100个整数。整数序列是相同的,这是预期的并且符合Java文档。

第二对是从0到99之间生成100个整数然后创建一个具有相同种子的新Random,并生成0到99之间的100个整数,除了在每10个整数之后,通过交替调用调用相同的Random对象发生nextBoolean和nextBytes。您可以在结果中看到序列是可重复的,并且调用相同的Random对象的其他下一个方法会影响nextInt的序列。您还可以看到nextInt中的常规模式仍在继续,但在序列的稍后阶段。如果每次对同一个随机ojbect的其他下一个方法的交错调用并不完全相同,则整数序列也不会相同。

使用种子123456789L两次调用nextInt()100个0到99之间的整数

第一组100次nextInt(100)调用...

  

65 0 83 44 90 54 33 7 97 87

     

41 61 64 82 24 61 60 89 30 79

     

42 86 38 54 61 25 98 20 99 88

     

65 33 91 30 61 64 27 74 80 13

     

58 63 66 38 34 89 46 5 88 79

     

50 18 5 24 65 63 58 6 73 80

     

84 5 33 1 58 29 9 87 0 83

     

1 75 84 81 16 2 8 14 98 26

     

64 28 40 50 33 70 81 57 71 18

     

58 37 36 48 71 28 95 77 74 92

第二组100次nextInt(100)调用......

  

65 0 83 44 90 54 33 7 97 87

     

41 61 64 82 24 61 60 89 30 79

     

42 86 38 54 61 25 98 20 99 88

     

65 33 91 30 61 64 27 74 80 13

     

58 63 66 38 34 89 46 5 88 79

     

50 18 5 24 65 63 58 6 73 80

     

84 5 33 1 58 29 9 87 0 83

     

1 75 84 81 16 2 8 14 98 26

     

64 28 40 50 33 70 81 57 71 18

     

58 37 36 48 71 28 95 77 74 92

如您所见,我得到了完全相同的结果。 现在,如果我在第二个序列中每隔10次调用nextInt()注入对nextBoolean和nextBytes的交替调用,会发生这种情况。

使用种子123456789L两次调用nextInt()100个0到99之间的整数

第一组100次nextInt(100)调用...

  

65 0 83 44 90 54 33 7 97 87

     

41 61 64 82 24 61 60 89 30 79

     

42 86 38 54 61 25 98 20 99 88

     

65 33 91 30 61 64 27 74 80 13

     

58 63 66 38 34 89 46 5 88 79

     

50 18 5 24 65 63 58 6 73 80

     

84 5 33 1 58 29 9 87 0 83

     

1 75 84 81 16 2 8 14 98 26

     

64 28 40 50 33 70 81 57 71 18

     

58 37 36 48 71 28 95 77 74 92

第二组100次nextInt(100)调用在每次调用nextInt(100)之后交替调用nextBoolean()和nextBytes(byte [10])...

  

65 0 83 44 90 54 33 7 97 87

     

     

61 64 82 24 61 60 89 30 79 42

     

字节:-75 -111 34 -128 -92 23 95 -112 100 -76

     

61 25 98 20 99 88 65 33 91 30

     

     

64 27 74 80 13 58 63 66 38 34

     

字节:-118 -57 19 -74 36 -70 31 114 -125 -61

     

88 79 50 18 5 24 65 63 58 6

     

     

80 84 5 33 1 58 29 9 87 0

     

字节:63 -82 -79 93 -126 2 23 2 -90 122

     

84 81 16 2 8 14 98 26 64 28

     

     

50 33 70 81 57 71 18 58 37 36

     

字节:-8 89 73 71 -25 -104 -28 12 -32 -110

     

95 77 74 92 92 78 36 99 78 61

     

     

66 39 19 18 19 99 41 68 38 48

     

字节:64 -71 126 97 17 -6 -120 94 73 64

注意在结果模式中,nextBoolean interleaved eats使用nextInt序列中的一个整数值,而nextBytes(byteArray)其中byteArray被声明为byte [10],它使用了nextInt序列中的三个整数值。

答案 5 :(得分:-1)

如果你想每次都获得相同的值,为什么不直接返回一个固定的int,它是由一次调用Random设置的?

答案 6 :(得分:-1)

另一种可能性是您创建自己的类并使用随机数生成器创建的列表或预生成的“随机”值填充它。据我所知,这是Doom用来降低网络游戏中数据传输的技术。所有玩家都有相同的随机数表用于计算损害,因此实际损坏数据不会在网络上传输。

每日WTF都有一个关于应用程序的故事,其中需要实际使用“随机化”列表,该列表将始终使用:

http://thedailywtf.com/Articles/More-or-Less-Random.aspx