[英]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.