2 回答
TA贡献1777条经验 获得超10个赞
这不可能。许多上限可以产生相同的输出。例如,对 Ideone的快速测试显示了 1000000 下的 9 个可能边界,这将产生 235 的输出,种子 532(800 不是其中之一):237、369、711、3239、9717、29151、505164、155164、15164和 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
并终止做的时候。
要给出 的正确值val
,bound
必须是一个bits - val
大于的因数val
。(有时bits - val
会是 0,任何大于它的整数val
都会通过。)要终止 do-while,bits - val + (bound-1)
一定不能溢出。因此,落入这种情况的可能界限bits - val
是一定范围内的因子,而不是 2 的幂。
至于最后一个案例,我不想经历它,所以这将“留给读者作为练习”。(这是最困难的情况,困难在于弄清楚bound
当您不知道时哪些值会导致溢出val
,而这比我花费的时间更长。)
TA贡献1815条经验 获得超10个赞
这是一种寻找隐藏边界的实验方法。获取随机对象的副本并记录其输出。创建where is max int 的n
实例。对于这些实例中的每一个,使用它们的索引作为 的参数。仅存储遵循原始序列的实例。继续淘汰候选人,直到只剩下一个。Random
n
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
添加回答
举报