如何在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?
答案 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
不是很令人兴奋,但是连续的种子只需几秒就能产生不同的输出,正如预期的那样。