2014-11-06 66 views
3

我有我的函數應該返回一個隨機數的下列問題。當我想通過調用該函數來生成幾個數字時,它們是完全一樣的。我怎樣才能解決我調用函數時始終返回相同數字的問題?我需要隨機保持功能。阿達隨機數是相同的

下面是代碼:

with Ada.Numerics.discrete_Random 

function generate_random_number (n: in Positive) return Integer is 
     subtype Rand_Range is Integer range 0 .. n; 
     package Rand_Int is new Ada.Numerics.Discrete_Random(Rand_Range); 
     use Rand_Int; 
     gen : Rand_Int.Generator; 
     ret_val: Rand_Range; 
    begin 
     Rand_Int.Reset(gen); 
     ret_val := Random(gen); 

     return ret_val; 
    end; 
+0

看到這個問題:http://stackoverflow.com/questions/21245051/ada-seeding-random。我對Ada並不熟悉,但看起來好像每次都使用相同的數字重新編號,即使粗略查看您的代碼並不能說明它如何。 – 2014-11-06 18:11:53

+0

如果您每次都返回相同的號碼,那告訴我您每次都發送相同的種子,而不是按順序接收下一個。 – 2014-11-06 18:12:10

+0

這是種子所有的時間,因爲當我稱這個函數兩次延遲幾秒鐘,它返回另一個隨機。有一條線應該重置發生器,但看起來不起作用。 – 2014-11-06 18:18:14

回答

1

隨機發生器gen不應該是本地的功能。目前,您正在重新創建每個generate_random_number調用並初始化它,因此您始終得到相同的結果並不奇怪。

如果您製作gen - 例如 - 一個全局變量,初始化一次,然後每次使用它,您將得到一個新的隨機數。 (是的,全局變量是不好的,但見下面)

不幸的是,這對function generate_random_number (n: in Positive)的語義沒有特別好的發揮,它可以每次不同地限制隨機數的範圍。最簡單的解決方法是使gen返回任何有效整數,並使用模塊化算法爲每個呼叫返回正確範圍內的數字。這將起作用,但您應該意識到它可能會引入加密弱點,超出我的分析技能。

如果是這種情況,您將需要不同的方法,例如爲您需要的每個範圍創建一個不同的隨機生成器;注意以不同方式播種(重置)它們,否則可能再次存在加密弱點,例如不同生成器之間的相關性。

現在,全球變量對於任何語言的所有常見原因而言都是糟糕的結構。所以更好的方法是通過將其包裝在一個包中來使其成爲一種資源。

package RandGen is 
    function generate_random_number (n: in Positive) return Positive; 
end RandGen; 

而這就是所有客戶需要看到的。

with Ada.Numerics.discrete_Random; 
package body RandGen is 

    subtype Rand_Range is Positive; 
    package Rand_Int is new Ada.Numerics.Discrete_Random(Rand_Range); 

    gen : Rand_Int.Generator; 

    function generate_random_number (n: in Positive) return Integer is 
    begin 
     return Rand_Int.Random(gen) mod n; -- or mod n+1 to include the end value 
    end generate_random_number; 

-- package initialisation part 
begin 
    Rand_Int.Reset(gen); 
end RandGen; 

編輯::拒絕外的範圍內的值的雅各的建議是更好,但效率低,如果n大於發電機範圍小得多的封裝如下實現的。一種解決方案可能是創建多個生成器,並讓generate_random_number函數選擇一個覆蓋0..N的函數,浪費最小。

+0

永遠不要使用'mod'來限制隨機數的間隔。拒絕過多的值! (除此之外,您的解釋和建議都很好。) – 2014-11-08 08:15:38

+0

@Jacob - 感謝您的更正! – 2014-11-08 10:31:01

+0

所有解決方案都很好,謝謝。因此,您的解決方案在我的程序中以大多數方式匹 – 2014-11-27 11:52:29

2

Random過程只用一個參數應該發起與「時間相關的狀態」的隨機數發生器。但是,如果連續多次被調用,程序使用的「時間」很可能每次都是相同的,因爲程序運行速度可能比時鐘分辨率快。 (嘗試使用類似在generate_random_number兩種用法之間delay 0.5測試;最有可能你會得到兩種不同的結果)

在任何情況下,預期使用一個隨機數生成器是使用就可以了Reset一次設置種子,然後生成一個從種子開始的隨機數序列。通過這樣做,您也可以每次都使用相同的種子,以獲得可重複的隨機數序列,以便進行測試;或者你可以使用時間依賴種子。但是,每次需要隨機數字時重置隨機數發生器不是正常或推薦的使用RNG的方法。因此,您需要將Reset呼叫移出generate_random_number。不幸的是,這也意味着即使參數n在每次通話中都會有所不同,也必須使用相同的發生器,這意味着您可能會被迫使用Float_Random而不是Discrete_Random

P.S.進一步研究,我在G.2.5中發現:「對時間相關復位過程的兩個不同調用應將發生器復位到不同狀態,前提是呼叫在時間上至少分開一秒而不是更多「我強調這一點。」我相信,當你嘗試它時,呼叫間隔不到一秒鐘。

+0

當我刪除重置調用時,無論何時調用函數或執行程序時,函數都會返回相同的值。當然,我可以在我的函數中生成一些數字然後記住它,但是我的程序中需要大約10^10個隨機數在指定範圍內。每次我需要來自不同範圍的隨機數,這就是使用一個參數保持其功能的原因。 – 2014-11-06 18:57:20

+0

@PaulDew對,你不能每次調用你的過程都有一個新的聲明。我認爲你必須使用Float_Random來做你自己的計算 - 對不起。 – ajb 2014-11-06 19:03:23

+0

RE P.S. :正如你所說。我嘗試了一點,當我在另一個序列中執行程序時,這些隨機數是另一個(但是相同)。 – 2014-11-06 23:28:57

0

假設上限可確定當啓動程序:

Random(規格):

with Generic_Random; 
with Upper_Limit_Function; 
package Random is new Generic_Random (Upper_Limit => Upper_Limit_Function); 

一般軟件包Generic_Random(規格):

generic 
    Upper_Limit : Positive; 
package Generic_Random is 
    subtype Values is Natural range 0 .. Upper_Limit; 
    function Value return Values; 
end Generic_Random; 

通用包Generic_Random(body):

with Ada.Numerics.Discrete_Random; 
package body Generic_Random is 
    package Random is new Ada.Numerics.Discrete_Random (Values); 

    Source : Random.Generator; 

    function Value return Values is 
    begin 
     return Random.Random (Source); 
    end Value; 
begin 
    Random.Reset (Source); 
end Generic_Random; 
+0

如果允許您重寫函數說明,這顯然是正確的方法! – 2014-11-08 10:38:11