1 // Copyright (c) 2011 The LevelDB Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. See the AUTHORS file for names of contributors. 4 5 #ifndef STORAGE_LEVELDB_UTIL_RANDOM_H_ 6 #define STORAGE_LEVELDB_UTIL_RANDOM_H_ 7 8 #include <stdint.h> 9 10 namespace leveldb { 11 12 // A very simple random number generator. Not especially good at 13 // generating truly random bits, but good enough for our needs in this 14 // package. 15 class Random { 16 private: 17 uint32_t seed_; 18 public: Random(uint32_t s)19 explicit Random(uint32_t s) : seed_(s & 0x7fffffffu) { } Next()20 uint32_t Next() { 21 static const uint32_t M = 2147483647L; // 2^31-1 22 static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 23 // We are computing 24 // seed_ = (seed_ * A) % M, where M = 2^31-1 25 // 26 // seed_ must not be zero or M, or else all subsequent computed values 27 // will be zero or M respectively. For all other values, seed_ will end 28 // up cycling through every number in [1,M-1] 29 uint64_t product = seed_ * A; 30 31 // Compute (product % M) using the fact that ((x << 31) % M) == x. 32 seed_ = static_cast<uint32_t>((product >> 31) + (product & M)); 33 // The first reduction may overflow by 1 bit, so we may need to 34 // repeat. mod == M is not possible; using > allows the faster 35 // sign-bit-based test. 36 if (seed_ > M) { 37 seed_ -= M; 38 } 39 return seed_; 40 } 41 // Returns a uniformly distributed value in the range [0..n-1] 42 // REQUIRES: n > 0 Uniform(int n)43 uint32_t Uniform(int n) { return Next() % n; } 44 45 // Randomly returns true ~"1/n" of the time, and false otherwise. 46 // REQUIRES: n > 0 OneIn(int n)47 bool OneIn(int n) { return (Next() % n) == 0; } 48 49 // Skewed: pick "base" uniformly from range [0,max_log] and then 50 // return "base" random bits. The effect is to pick a number in the 51 // range [0,2^max_log-1] with exponential bias towards smaller numbers. Skewed(int max_log)52 uint32_t Skewed(int max_log) { 53 return Uniform(1 << Uniform(max_log + 1)); 54 } 55 56 // Shuffle the array into random order Shuffle(int * array,int n)57 void Shuffle(int *array, int n) { 58 if (n > 1) { 59 int i; 60 for (i=0; i<n-1; i++) { 61 int j = i + Next() / (2147483647 / (n-i) + 1); 62 int t = array[j]; 63 array[j] = array[i]; 64 array[i] = t; 65 } 66 } 67 } 68 }; 69 70 } // namespace leveldb 71 72 #endif // STORAGE_LEVELDB_UTIL_RANDOM_H_ 73