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

Seeding SML/NJ's RNG on a Windows machine

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

函数 Random.rand() 接受一对整数并使用它们作为随机数生成器的种子。根据我使用其他编程语言的经验,我希望有一种相对简单的方法可以根据系统时钟(类似于 C 中的 srand(time(null));)来播种它。除非我忽略了一些明显的东西,否则似乎没有任何直接的方法,至少如果你使用 Windows.

我在 SML 中找到的最接近 time(null) 的是 Posix.ProcEnv.time, which returns Unix epoch time. Unfortunately, the Posix structures are not part of the Windows download, and the Windows 结构(它似乎不包含 time.

的任何直接类似物

Timer 结构确实有确定 elapsed 实时的方法。我可以编写一个函数来执行大约半秒的无意义计算,计算需要多长时间,然后找出一种方法从中提取几个整数。但是:1) 对于大多数语言中微不足道的事情来说,这是一项非常多的工作,2) 更重要的是——它似乎可能会导致相同的种子在一定比例的时间内被重复使用。

我的另一个想法是,如果我可以访问 Windows 环境变量 "TIME",我就可以使用它。以下将时间打印到 repl:

OS.Process.system "TIME/T";

但不提供对打印字符串的任何编程访问。

OS.Process.getEnv "TIME";

听起来很有希望,但是 returns NONE.

如果 SML/NJ 中确实没有简单的解决方案 -- 是否有适用于 SML 的其他一些实现的选项,例如 Poly/ML?

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

val now: unit -> t

@matt 自己回答了以便携方式读取系统时钟的问题。为了补充他的回答,这里有一个种子函数。作为一个技术问题,自 1970 年以来经过的秒数对于 SML/NJ 31 位整数来说太大了。我当然可以使用大整数,但一个简单的解决方案似乎是在转换为 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

不是很令人兴奋,但相隔几秒钟的连续播种产生了不同的输出,正如预期的那样。