在 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
不是很令人兴奋,但相隔几秒钟的连续播种产生了不同的输出,正如预期的那样。
如何在 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
不是很令人兴奋,但相隔几秒钟的连续播种产生了不同的输出,正如预期的那样。