[m-rev.] for review: Add random.init/3
Paul Bone
paul at bone.id.au
Wed May 25 15:55:50 AEST 2016
For review by anyone
----
Add random.init/3
random.init/3 makes it easier to seed the random number generator. It will
calculate a seed based on the current time and, if known, the process ID.
This is sufficient for simple applications but shouldn't be used for
security-sensitive applications.
library/random.m:
As above.
NEWS:
Announce the new addition.
---
NEWS | 3 +++
library/random.m | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+)
diff --git a/NEWS b/NEWS
index 5628bb5..7388ba0 100644
--- a/NEWS
+++ b/NEWS
@@ -336,6 +336,9 @@ Changes to the Mercury standard library:
- is_empty/1
+* We have added a new init/3 predicate to the random module. This predicate
+ seeds the PRNG using the current time and process ID (if known).
+
Changes to the Mercury compiler:
* We have added a new option --warn-dead-preds. While the existing option
diff --git a/library/random.m b/library/random.m
index 2ce0150..5aacf1f 100644
--- a/library/random.m
+++ b/library/random.m
@@ -51,6 +51,7 @@
:- module random.
:- interface.
+:- import_module io.
:- import_module list.
%---------------------------------------------------------------------------%
@@ -65,6 +66,16 @@
%
:- pred init(int::in, supply::uo) is det.
+ % init(RS, !IO).
+ %
+ % Creates a supply of random numbers seeded based on the current time of
+ % day and the process ID (if known).
+ %
+ % NOTE: This is not suitable for security but is still suitable for some
+ % applications.
+ %
+:- pred init(supply::uo, io::di, io::uo) is det.
+
% random(Num, !RS).
%
% Extracts a number Num in the range 0 .. RandMax from the random number
@@ -130,6 +141,7 @@
:- import_module array.
:- import_module int.
+:- import_module time.
:- type supply
---> rs(int). % I(j)
@@ -141,6 +153,42 @@ params(9301, 49297, 233280).
init(I0, rs(RS)) :-
copy(I0, RS).
+init(RS, !IO) :-
+ get_pid(Pid, !IO),
+ time(Time, !IO),
+ localtime(Time) = TM,
+ TM = tm(Year, Month, Day, Hour, Min, Sec, _, _, _),
+ % For seeding the RNG 31 days in a month is fine.
+ Now = Sec * 60*60*24*31*12 +
+ Min * 60*24*31*12 +
+ Hour * 24*31*12 +
+ Day * 31*12 +
+ Month * 12 +
+ Year,
+ ( if Pid = 0 then
+ Seed = Now
+ else
+ Seed = (Now << 16) \/ Pid
+ ),
+ init(Seed, RS).
+
+:- pred get_pid(int::out, io::di, io::uo) is det.
+
+:- pragma foreign_proc("C",
+ get_pid(PID::out, _IO0::di, _IO::uo),
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+#if defined (WIN32) && !defined (__CYGWIN32__)
+ PID = GetCurrentProcessId();
+#elif MR_HAVE_GETPID
+ PID = getpid();
+#else
+ PID = 0;
+#endif
+").
+
+get_pid(0, !IO).
+
random(I, rs(RS0), rs(RS)) :-
RS0 = I0,
random.params(A, C, M),
--
2.8.1
More information about the reviews
mailing list