簡體   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