Seeding SML/NJ's RNG on a Windows machine

拈花ヽ惹草 提交于 2019-12-13 00:18:14

问题


How to seed SML/NJ's random number generator on a Windows machine?

The function Random.rand() takes a pair of integers and uses them to seed the random number generator. Based on my experience with other porgramming languages, I would expect there to be a relatively easy way to seed it based on the system clock (something like srand(time(null)); in C). Unless I am overlooking something obvious, there doesn't seem to be any straightforward way, at least if you are using Windows.

The closest I can find to time(null) in SML is Posix.ProcEnv.time, which returns Unix epoch time. Unfortunately, the Posix structures are not part of the Windows download, and the Windows structure (which is) doesn't seem to include any direct analogue of time.

The Timer structure does have ways of determining elapsed real time. I could write a function which does about half a second of meaningless calculation, time how long it takes, and figure out a way to extract a couple of integers from that. But: 1) this is an awful lot of work for something which is trivial in most languages, 2) more importantly -- it seems likely to result in the same seed being reused a non-trivial percentage of the times.

Another idea I had is that if I could access the Windows environment variable "TIME" I could use that. The following prints the time to the repl:

OS.Process.system "TIME/T";

but doesn't give any programatic access to the printed string.

OS.Process.getEnv "TIME";

sounds promising, but returns NONE.

If there really is no easy solution in SML/NJ -- are there options which work for some of the other implementations of SML such as Poly/ML?


回答1:


The Basis Library's TIME signature has a function for returning the current time.

val now: unit -> t



回答2:


@matt answered the question itself as far as getting the system clock reading in a portable way. To complement his answer, here is a seed function. As a technical problem, the number of elapsed seconds since 1970 is too large for an SML/NJ 31-bit int. I could use large ints of course, but a simple solution seemed to be to just reduce by 1.48 billion before converting to an int (and to use the decimal part of the time to get the second int seed parameter):

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;

There is almost definitely a more principled way to do this, but the above works:

- 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

Not very exciting, but successive seedings sepearated by just a few seconds produced different outputs, as expected.



来源:https://stackoverflow.com/questions/42351292/seeding-sml-njs-rng-on-a-windows-machine

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!