Replace rand48 with std::linear_congruential_engine in simulator (#110)

diff --git a/src/aarch64/logic-aarch64.cc b/src/aarch64/logic-aarch64.cc
index 4d50568..e1416ea 100644
--- a/src/aarch64/logic-aarch64.cc
+++ b/src/aarch64/logic-aarch64.cc
@@ -168,11 +168,12 @@
 
 
 uint64_t Simulator::GenerateRandomTag(uint16_t exclude) {
-  uint64_t rtag = nrand48(rand_state_) >> 28;
+  // Generate a 4 bit integer from a 48bit random number
+  uint64_t rtag = rand_gen_() >> 44;
   VIXL_ASSERT(IsUint4(rtag));
 
   if (exclude == 0) {
-    exclude = nrand48(rand_state_) >> 27;
+    exclude = rand_gen_() >> 44;
   }
 
   // TODO: implement this to better match the specification, which calls for a
@@ -7487,7 +7488,7 @@
 
   // Non-faulting loads are allowed to fail arbitrarily. To stress user
   // code, fail a random element in roughly one in eight full-vector loads.
-  uint32_t rnd = static_cast<uint32_t>(jrand48(rand_state_));
+  uint32_t rnd = static_cast<uint32_t>(rand_gen_());
   int fake_fault_at_lane = rnd % (LaneCountFromFormat(vform) * 8);
 
   for (int i = 0; i < LaneCountFromFormat(vform); i++) {
diff --git a/src/aarch64/simulator-aarch64.cc b/src/aarch64/simulator-aarch64.cc
index 83d1649..9f5c56d 100644
--- a/src/aarch64/simulator-aarch64.cc
+++ b/src/aarch64/simulator-aarch64.cc
@@ -594,9 +594,8 @@
   guard_pages_ = false;
 
   // Initialize the common state of RNDR and RNDRRS.
-  uint16_t seed[3] = {11, 22, 33};
-  VIXL_STATIC_ASSERT(sizeof(seed) == sizeof(rand_state_));
-  memcpy(rand_state_, seed, sizeof(rand_state_));
+  uint64_t seed = (11 + (22 << 16) + (static_cast<uint64_t>(33) << 32));
+  rand_gen_.seed(seed);
 
   // Initialize all bits of pseudo predicate register to true.
   LogicPRegister ones(pregister_all_true_);
@@ -6947,8 +6946,8 @@
           break;
         case RNDR:
         case RNDRRS: {
-          uint64_t high = jrand48(rand_state_);
-          uint64_t low = jrand48(rand_state_);
+          uint64_t high = rand_gen_();
+          uint64_t low = rand_gen_();
           uint64_t rand_num = (high << 32) | (low & 0xffffffff);
           WriteXRegister(instr->GetRt(), rand_num);
           // Simulate successful random number generation.
diff --git a/src/aarch64/simulator-aarch64.h b/src/aarch64/simulator-aarch64.h
index 6e36246..0a8d2fe 100644
--- a/src/aarch64/simulator-aarch64.h
+++ b/src/aarch64/simulator-aarch64.h
@@ -29,6 +29,7 @@
 
 #include <memory>
 #include <mutex>
+#include <random>
 #include <unordered_map>
 #include <vector>
 
@@ -5431,11 +5432,15 @@
   CPUFeaturesAuditor cpu_features_auditor_;
   std::vector<CPUFeatures> saved_cpu_features_;
 
-  // State for *rand48 functions, used to simulate randomness with repeatable
+  // linear_congruential_engine, used to simulate randomness with repeatable
   // behaviour (so that tests are deterministic). This is used to simulate RNDR
   // and RNDRRS, as well as to simulate a source of entropy for architecturally
   // undefined behaviour.
-  uint16_t rand_state_[3];
+  std::linear_congruential_engine<uint64_t,
+                                  0x5DEECE66D,
+                                  0xB,
+                                  static_cast<uint64_t>(1) << 48>
+      rand_gen_;
 
   // A configurable size of SVE vector registers.
   unsigned vector_length_;