繁体   English   中英

如何获得用于生成随机数的范围?

[英]How can I get the range used in generating random number?

我使用Java中的种子生成随机数。 知道最终的输出是235,种子编号是532,如何获得Java中的intBound编号? 例如

int randomNumber
int seed=532;
int intBound=800;
Random rand = Random(seed); 
randomNumber=rand.nextInt(intBound);

System.out.println("The generated Random number using the above seed and int bound is:- "+randomNumber);
//Results is: The generated Random number using the above seed and int bound is: 235

这个问题的简化数学版本是:仅知道数学公式的两个值,您如何产生第三个值? 例如1 + 2 = 3,这也意味着如果我们只知道2个值和所使用的公式,我们就可以很容易地知道第三个值,而知道要使用哪个公式来获得结果。

这是不可能的。 许多上限可以产生相同的输出。 例如,对Ideone进行的快速测试显示,在1000000以下的9个可能的界限将产生带有种子532的235输出(而800不是其中之一):237、369、711、3239、9717、29151、50549、151647,和454941。

import java.util.*;

class Test
{
    public static void main (String[] args) throws java.lang.Exception
    {
        List<Integer> bounds = new ArrayList<Integer>();
        for (int i = 1; i < 1000000; i++) {
            Random rng = new Random(532);
            if (rng.nextInt(i) == 235) {
                bounds.add(i);
            }
        }
        System.out.println(bounds);
    }
}

您能做的最好的就是确定可能的界限。 nextInt(int)的实现要求等效于

 public int nextInt(int bound) {
   if (bound <= 0)
     throw new IllegalArgumentException("bound must be positive");

   if ((bound & -bound) == bound)  // i.e., bound is a power of 2
     return (int)((bound * (long)next(31)) >> 31);

   int bits, val;
   do {
       bits = next(31);
       val = bits % bound;
   } while (bits - val + (bound-1) < 0);
   return val;
 }

该算法提供特定输出的方式可以分为三种可能性:

  • bound是二的幂
  • bound不是2的幂,并且循环在第一次迭代时终止
  • bound不是2的幂,并且循环继续经过第一次迭代

电源的两bound的情况下很容易-只需尝试幂的每两个bound ,在一个适合int 只有31个。 您可以对此进行优化,但是没有太多意义。

可以通过计算next(31)本来可以是的值来处理第一个迭代的非二次幂情况(可以通过播入Random实例并调用next(31) ),然后查看bound将同时给出val的正确值并终止do-while。

为了给出正确的val值, bound必须是val一个因数bits - val大于val (有时, bits - val将为0,并且大于val任何整数都将通过。)要终止do-while, bits - val + (bound-1)一定不能溢出。 因此,落入这种情况的可能边界是bits - val因数bits - val在一定范围内,而不是2的幂。

至于最后一种情况,我不想经历,所以将“留给读者练习”。 (这是最困难的情况,遇到困难,例如找出不知道val时, bound值将导致溢出,这将比我花更多的时间。)

这是找到隐藏边界的实验方法。 获取随机对象的副本并记录其输出。 创建nRandom实例,其中n是max int。 对于这些Random实例中的每一个,都将其索引用作nextInt的参数。 仅存储遵循原始序列的Random实例。 继续消除候选人,直到只剩下一个。

请考虑下表。 在最上面,我们用对随机值进行采样的迭代为列命名。 在一侧,我们有具有相同种子的序列,这些序列具有不同的绑定值。 中间单元格中的值表示为给定的Random实例和迭代检索的随机值。

第一次遍历所有可能的整数后,我们剩下4个可能的候选项。 我们将继续与权威机构进行比较,直到仅剩下一名可能的候选人为止。 如果您未从授权机构提供足够的样本,则可能会留下多个匹配的上限值候选者。

在此处输入图片说明

public static void main(String [] args) throws Exception {
    final Scanner scanner = new Scanner(System.in);

    System.out.print("Please enter the seed number: ");
    final long seed = scanner.nextLong();
    System.out.print("Please enter the hidden bound: ");
    final int bound = scanner.nextInt();

    final long start = System.nanoTime();

    final IntSupplier original = rand(seed, bound);
    final int firstRandom = original.getAsInt();

    Map<Integer, IntSupplier> candidates = new HashMap<>();
    for (int i = 1; i < Integer.MAX_VALUE; i++) {
        final IntSupplier candidate = rand(seed, i);
        if (firstRandom == candidate.getAsInt()) {
            candidates.put(i, candidate);
        }
    }

    int iterations = 1;
    while (candidates.size() > 1) {
        iterations += 1;
        final int current = original.getAsInt();

        Map<Integer, IntSupplier> survivors = new HashMap<>();
        for (Map.Entry<Integer, IntSupplier> entry : candidates.entrySet()) {
            if (entry.getValue().getAsInt() == current) {
                survivors.put(entry.getKey(), entry.getValue());
            }
        }
        candidates = survivors;
    }

    if (candidates.size() == 1) {
        System.out.println("Upper bound is " + candidates.keySet().iterator().next());
    } else {
        System.out.println("No upper bound found");
    }
    System.out.println("Completed in " + iterations +  " iterations");

    final long end = System.nanoTime();
    System.out.println("Completed in " + (end - start) / Math.pow(10,9) + "seconds");
}

static IntSupplier rand(long seed, int bound) {
    final Random rand = new Random(seed);
    return () -> rand.nextInt(bound);
}

产生输出:

Please enter the seed number: 532
Please enter the hidden bound: 800
Upper bound is 800
Completed in 4 iterations
Completed in 46.778499624 seconds

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM