2017-02-20 82 views
1

如何在Windows機器上播種SML/NJ的隨機數發生器?在Windows機器上播種SML/NJ的RNG

函數Random.rand()需要一對整數並使用它們來爲隨機數生成器播種。根據我對其他編程語言的經驗,我期望有一種基於系統時鐘的相對簡單的方法(類似於C中的srand(time(null));)。除非我忽略了一些明顯的東西,否則似乎沒有任何直接的方法,至少如果您使用的是Windows。

SML中最接近time(null)的是Posix.ProcEnv.time,它返回Unix紀元時間。不幸的是,Posix結構不是Windows下載的一部分,並且Windows結構(它)似乎不包括任何直接模擬time

Timer結構確實有確定已過期實時的方法。我可以編寫一個函數,它可以執行大約半秒的無意義計算,計算需要多長時間,並找出從中提取幾個整數的方法。但是:1)對於在大多數語言中微不足道的東西來說,這是一項可怕的工作,2)更重要的是 - 似乎可能會導致相同的種子被重複使用的時間百分比不平等。

我的另一個想法是,如果我可以訪問Windows環境變量"TIME"我可以使用它。以下打印到repl的時間:

OS.Process.system "TIME/T"; 

但是不給出對打印字符串的任何編程式訪問。

OS.Process.getEnv "TIME"; 

聽起來很有希望,但是返回NONE

如果在SML/NJ中確實沒有簡單的解決方案 - 是否有可用於SML的某些其他實現(如Poly/ML)的選項?

回答

3

Basis Library的TIME簽名具有返回當前時間的功能。

val now: unit -> t 
+0

這應該工作。奇怪的是,我曾多次看過「時間」,但忽略了這一點。我得到了這樣的印象,即'時間'被設計爲解析從'Timer'返回的值,但是它本身不包含時鐘信息。 –

+0

我在正常的基礎文檔中錯過了它,將更新答案以反映其標準功能 – matt

2

@matt回答了這個問題本身,以便攜式方式獲取系統時鐘讀數。爲了補充他的回答,這裏是種子功能。作爲一個技術問題,自從1970年以來的秒數對於SML/NJ 31位int來說太大了。當然,我可以使用大整數,但是一個簡單的解決方案似乎是在轉換爲int之前減少14.8億(並使用小數部分的時間來獲得第二個int種子參數):

fun seed() = 
    let 
     val r = Time.toReal(Time.now()) - 1.48e9 
     val f = Real.realFloor(r) 
     val d = r - f 
     val i = Real.floor(f) 
     val j = Real.floor(1000.0*d) 
    in 
     Random.rand(i,j) 
    end; 

有幾乎可以肯定要做到這一點更原則性的方式,但上述作品:

- val s = seed(); 
val s = 
    RND 
    {borrow=ref false,congx=ref 0wx4B7CD4CA,index=ref 0, 
    vals=[|0wx40E9888B,0wx6F1B97FD,0wx4011C479,0wx2012F528,0wx3CDC0237, 
      0wx7C36E91D,0wx5361B64D,0wx4B61A297,0wx61823821,0wx7C6CD6BD, 
      0wx1683CA4D,0wx670A75AF,...|]} : Random.rand 
- Random.randRange(1,100) s; 
val it = 35 : int 
- val s = seed(); 
val s = 
    RND 
    {borrow=ref false,congx=ref 0wx512EBCFC,index=ref 0, 
    vals=[|0wx456E115A,0wx27817499,0wx46A6BE48,0wx2C79BB3,0wx3FF47B4D, 
      0wx5B48FC93,0wx53C3647F,0wx32E40F5A,0wx157AB4C8,0wx16E750D, 
      0wx78BD3EA3,0wx7885CA23,...|]} : Random.rand 
- Random.randRange(1,100) s; 
val it = 73 : int 

所產生不同的輸出只需要幾秒鐘無法相依不是很令人興奮,但連續的種子隊,符合市場預期。