在Windows机器上播种SML / NJ的RNG

时间:2017-02-20 17:54:07

标签: sml smlnj

如何在Windows机器上播种SML / NJ的随机数生成器?

函数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?

2 个答案:

答案 0 :(得分:3)

Basis Library的TIME签名具有返回当前时间的功能。

val now: unit -> t

答案 1 :(得分:2)

@matt回答了问题本身,只要以便携方式获取系统时钟读数即可。为了补充他的答案,这是一个种子功能。作为一个技术问题,自1970年以来经过的秒数对于SML / NJ 31位int来说太大了。我当然可以使用大的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

不是很令人兴奋,但是连续的种子只需几秒就能产生不同的输出,正如预期的那样。