]> git.ipfire.org Git - thirdparty/make.git/commitdiff
Implement a simple xorshift 32bit random number generator
authorPaul Smith <psmith@gnu.org>
Mon, 26 Sep 2022 18:38:27 +0000 (14:38 -0400)
committerPaul Smith <psmith@gnu.org>
Sat, 1 Oct 2022 15:45:39 +0000 (11:45 -0400)
Avoid relying on the system random number generator for our random
shuffle, so that the same seed gives the same results on all systems.
This generator doesn't need to be amazing, just pretty good, so don't
bother with xorshift* or xorshift+, etc.

* src/makeint.h: Declare make_seed() and make_rand().
* src/misc.c (make_seed): Set the seed value for the RNG.
(make_rand): Return the next random number.  If the seed was not set
initialize it first.
* src/shuffle.c (shuffle_set_mode): If we don't get a seed from the
user just leave it unset (0).
(shuffle_deps_recursive): Use make_seed() not srand().
(random_shuffle_array): Use make_rand() not rand().

src/makeint.h
src/misc.c
src/shuffle.c

index b8dbc1ffa859a80dd9f65d2de74433be0298541e..00dded16cebb6710feb90035c9c1f35ea46d3e14 100644 (file)
@@ -537,6 +537,8 @@ void perror_with_name (const char *, const char *);
 unsigned int make_toui (const char*, const char**);
 char *make_lltoa (long long, char *);
 char *make_ulltoa (unsigned long long, char *);
+void make_seed (unsigned int);
+unsigned int make_rand ();
 pid_t make_pid ();
 void *xmalloc (size_t);
 void *xcalloc (size_t);
index 8f9be32886a4bbda0691ac5bcfb65ff4194e5031..48e4cb5e8bc174cfca58317c375ccd0170f2f81b 100644 (file)
@@ -78,6 +78,35 @@ make_ulltoa (unsigned long long val, char *buf)
   return buf;
 }
 
+/* Simple random number generator, for use with shuffle.
+   This doesn't need to be truly random, just pretty random.  Use our own
+   implementation rather than relying on the C runtime's rand() so we always
+   get the same results for a given seed, regardless of OS.  */
+
+static unsigned int mk_state = 0;
+
+void
+make_seed(unsigned int seed)
+{
+  mk_state = seed;
+}
+
+unsigned int
+make_rand()
+{
+  /* mk_state must never be 0.  */
+  if (mk_state == 0) {
+    mk_state = (unsigned int)(time (NULL) ^ make_pid ()) + 1;
+  }
+
+  /* A simple xorshift RNG.  */
+  mk_state ^= mk_state << 13;
+  mk_state ^= mk_state >> 17;
+  mk_state ^= mk_state << 5;
+
+  return mk_state;
+}
+
 /* Compare strings *S1 and *S2.
    Return negative if the first is less, positive if it is greater,
    zero if they are equal.  */
index 95f60bea6b61831cfbebf89449ea254095469310..5f68caf6c72bd517656e68a4f620667b8e57ba85 100644 (file)
@@ -82,9 +82,7 @@ shuffle_set_mode (const char *cmdarg)
     }
   else
     {
-      if (strcasecmp (cmdarg, "random") == 0)
-        config.seed = (unsigned int) (time (NULL) ^ make_pid ());
-      else
+      if (strcasecmp (cmdarg, "random") != 0)
         {
           /* Assume explicit seed.  */
           const char *err;
@@ -109,7 +107,7 @@ random_shuffle_array (void **a, size_t len)
       void *t;
 
       /* Pick random element and swap. */
-      unsigned int j = rand () % len;
+      unsigned int j = make_rand () % len;
       if (i == j)
         continue;
 
@@ -227,7 +225,7 @@ shuffle_deps_recursive (struct dep *deps)
 
   /* Set specific seed at the top level of recursion.  */
   if (config.mode == sm_random)
-    srand (config.seed);
+    make_seed (config.seed);
 
   shuffle_deps (deps);