2017-02-20 86 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 

所产生不同的输出只需要几秒钟无法相依不是很令人兴奋,但连续的种子队,符合市场预期。