[英]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
值将导致溢出,这将比我花更多的时间。)
这是找到隐藏边界的实验方法。 获取随机对象的副本并记录其输出。 创建n
个Random
实例,其中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.