随机数生成在Java中没有重复

时间:2013-03-09 06:55:03

标签: java cryptography

我想澄清伪随机数的生成。 我的问题是:

  • 是否有机会在伪随机数生成中获得重复数字?

  • 当我用Google搜索时,我发现了真正的随机数生成。我可以获得一些用于真正随机数生成的算法,以便我可以将其与

    一起使用
      

    SecureRandom.getInstance(字符串算法)

请优先考虑安全性。

4 个答案:

答案 0 :(得分:4)

1)是的,你通常可以在PRNG中重复数字。实际上,如果你应用鸽子洞原则,证明是非常简单的(即,假设你有一组32位无符号整数的PRNG;如果你生成超过2 ^ 32个伪随机数,你肯定会有至少生成至少2次的至少一个数字;实际上,这会更快地发生;通常PRNG的算法将循环一个序列,并且您有办法计算或估计该周期的大小,最后每个单个数字将开始重复,并且算法的图像通常是方式,方式小于您从中获取数字的集合。

如果您需要非重复数字(因为安全性似乎是您关心的问题,请注意这是安全性比允许重复数字的一系列(伪)随机数! !!),你可以这样做:

class NonRepeatedPRNG {
  private final Random rnd = new Random();
  private final Set<Integer> set = new HashSet<>();
  public int nextInt() {
    for (;;) {
      final int r = rnd.nextInt();
      if (set.add(r)) return r;
    }
  }
}

请注意,上面定义的nextInt方法可能永远不会返回!请谨慎使用。

2)不,没有“真正的随机数生成算法”这样的东西,因为算法是已知的,你可以控制并且可以预测(即,只运行它并且你有输出;你确切地知道下次使用相同的初始条件运行它时输出,而真正的RNG根据定义完全不可预测。

对于大多数常见的非安全相关应用程序(即科学计算,游戏等),PRNG就足够了。如果担心安全性(即,您需要加密的随机数),那么CSPRNG(加密安全PRNG)就足够了。

如果你的应用程序在没有真正随机性的情况下无法正常工作,我真的很想知道它的更多信息。

答案 1 :(得分:2)

是的,任何随机数生成器都可以重复。非重复随机数问题有三种通用解决方案:

  • 如果您需要大范围内的少数数字,请选择一个并拒绝 它是否重复。如果范围很大,那么这不会导致 反复尝试太多了。

  • 如果你想要一个小范围的很多数字,那么列出一个数字中的所有数字 数组并随机播放数组。 Fisher-Yates算法是数组的标准 洗牌。从随机数组中按顺序获取随机数。

  • 如果您想要大范围内的大量数字,请使用适当大小的数字 加密演算法。例如。对于64位数字使用DES并加密0,1,2,3 ...... 按顺序。输出保证唯一,因为加密是可逆的。

答案 2 :(得分:0)

伪RNG可以重复自己,但真正的RNG也可以重复自己 - 如果他们从不重复自己,他们就不会是随机的。

一旦用一些(~128位)真实熵播种的良好PRNG实际上与真正的RNG无法区分。与真正的RNG相比,你肯定不会得到明显更多的碰撞或重复。

因此,您不太可能需要真正的随机数生成器,但如果您确实在random.org检查了HTTP API。他们的API由真正的随机源支持。随机性来自大气噪声。

答案 3 :(得分:0)

如果PRNG或RNG从不重复数字,那实际上是......真的可以预测!想象一下PRNG超过1到8的数字。你看它打印出2,5,7,3,8,4,6。如果PRNG尽力不重复,现在你知道下一个数字将会是1 - 那不再是随机的了!

因此PRNG和RNG默认会产生重复的随机输出。如果你不想重复,你应该使用像Fisher-Yates Shuffle(http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)这样的混洗算法,以随机顺序随机混合你想要的数字数组。

此外,如果您需要为加密目的生成随机数源,请寻找适合您语言的加密PRNG提供商。只要它在加密方面很强大就应该没问题 - 真正的RNG要贵得多(或者需要延迟,比如使用random.org)而且通常不需要。