Jakub Kotur | 2ea66b3 | 2020-12-21 17:28:15 +0100 | [diff] [blame] | 1 | # oorandom |
| 2 | |
| 3 | [](https://crates.io/crates/oorandom) |
| 4 | [](https://docs.rs/oorandom) |
| 5 | [](https://builds.sr.ht/~icefox/oorandom?) |
| 6 | |
| 7 | # What is this? |
| 8 | |
| 9 | `oorandom` is a minimalistic pseudorandom number generator in Rust. For |
| 10 | those times when the `rand` crate is just too big and you want something |
| 11 | a bit dumber. |
| 12 | |
| 13 | More specifically, it implements ONE prng, which is currently a permuted |
| 14 | congruential generator (PCG). It may change if something better comes |
| 15 | along, but that seems unlikely and will probably be a major version |
| 16 | bump. It will give you `u32` or `u64`, and signed or floating-point |
| 17 | equivalents. It is also `#[no_std]`. Anything else is gravy. |
| 18 | |
| 19 | Thanks to Lokathor for making |
| 20 | [`randomize`](https://github.com/Lokathor/randomize), which inspired me |
| 21 | to do my own equivalent. |
| 22 | |
| 23 | The name comes from my attempts to find a good way to pronounce |
| 24 | `/dev/urandom`. |
| 25 | |
| 26 | Please direct questions, discussions and bugs to the [issue |
| 27 | tracker](https://todo.sr.ht/~icefox/oorandom). |
| 28 | |
| 29 | # Why use `oorandom` instead of... |
| 30 | |
| 31 | * `rand` -- `oorandom` is simpler and has zero choices you need to |
| 32 | make. It also compiles in 1/10th the time and has a stable API. |
| 33 | * `getrandom` -- They solve different problems; `getrandom` gives you |
| 34 | whatever secure randomness the OS decides to give you, not a |
| 35 | deterministic and seedable PRNG. It's generally a good idea to use |
| 36 | `getrandom` to seed this RNG though. |
| 37 | * `randomize` -- `randomize` used to be more complicated, but |
| 38 | `randomize` 3.x is quite similar to `oorandom` in functionality and |
| 39 | design. Go for it. |
| 40 | * `rand_pcg` and `rand_core` -- Yes you can take `rand` apart into its |
| 41 | pieces and use those individually, if you want to abandon having an |
| 42 | all-in-one solution, still deal with the lack of stability in |
| 43 | `rand_core` and actually figure out which pieces you need. It works |
| 44 | just fine. Seems more complicated than it needs to be though. |
| 45 | * `nanorand` -- `nanorand` uses the |
| 46 | [WyRand](https://github.com/wangyi-fudan/wyhash) PRNG algorithm, |
| 47 | which is supposedly faster than PCG and at least as good quality. I |
| 48 | haven't verified these claims, and I don't know of any *really* |
| 49 | thorough 3rd party investigation into them, though it apparently |
| 50 | passes [Dr. Lemire's tests](https://github.com/lemire/testingRNG). |
| 51 | So for now I personally consider WyRand to be in the "trust but |
| 52 | verify" level of quality. It's probably fine. |
| 53 | |
| 54 | # This is not... |
| 55 | |
| 56 | This is not cryptographically secure, and if you use it for crypto you |
| 57 | will get what you deserve. You are also in charge of choosing a useful |
| 58 | seed; the `getrandom` crate might be useful for that. |
| 59 | |
| 60 | This is also not optimized to be stupidly fast, but is basically just |
| 61 | as fast as `rustc` feels like making it. This means it is safe and robust |
| 62 | and portable and involves absolutely zero clever tricks. |
| 63 | |
| 64 | # Usage |
| 65 | |
| 66 | ```rust |
| 67 | use oorandom; |
| 68 | fn main() { |
| 69 | let some_seed = 4; |
| 70 | let mut rng = oorandom::Rand32::new(some_seed); |
| 71 | println!("Your random number is: {}", rng.rand_float()); |
| 72 | } |
| 73 | ``` |
| 74 | |
| 75 | If you want a nondeterministic seed, I recommend using the `getrandom` crate to produce one. |
| 76 | |
| 77 | # License |
| 78 | |
| 79 | MIT |
| 80 | |
| 81 | # A brief history of random numbers |
| 82 | |
| 83 | The usefulness of random numbers has been known for a long, long time |
| 84 | to people who also knew how to use slide rules. If you wanted to do |
| 85 | some math without the bother of coming up with all that pesky input |
| 86 | data from the real world, you might as well just use any ol' random numbers, |
| 87 | as long as there weren't any patterns in them to heck up the patterns you were |
| 88 | trying to look at. So in the first half |
| 89 | of the 20th century you had little old ladies named Edith spinning |
| 90 | roulette wheels or pulling bingo balls out of baskets and writing the |
| 91 | results down, which got assembled into giant tomes and published so |
| 92 | that engineering schools could buy them and have giant tomes sitting |
| 93 | on their shelves. Anyone who wanted some meaningless numbers could |
| 94 | pull the tome down, flip it open to a presumably-random page, and |
| 95 | there were all the random numbers anyone could want. The problem was |
| 96 | solved, and life was good. |
| 97 | |
| 98 | In late 1940's computers were invented, but they were far too big and |
| 99 | expensive to be put on the task of *intentionally* generating |
| 100 | nonsense, and things carried on as before. If you needed random |
| 101 | numbers in a computer program, you just got a pretty young lady named |
| 102 | Mary to transcribe part of the book to punch cards for you. |
| 103 | |
| 104 | Around the early 1960's computers got fast enough that Edith and Mary |
| 105 | couldn't keep up with them, so they got downsized and replaced with |
| 106 | more computers. To do this people came up with Linear Congruential |
| 107 | Generators (LCG's), which could generate lots of numbers numbers that |
| 108 | weren't really random, but sure looked random. LCG's worked well on |
| 109 | computers that even a second-rate university could afford, and so the |
| 110 | problem was solved, and life was good. |
| 111 | |
| 112 | At some unknown point in here, presumably sometime in the 60's or 70's, |
| 113 | someone seems to have invented Linear Feedback Shift Registers (LFSR's) |
| 114 | as well. These made random-looking numbers and were really easy to |
| 115 | implement in hardware compared to the LCG, which needed to do |
| 116 | complicated things like multiply numbers. The random-looking numbers |
| 117 | made by LFSR's were good enough for hardware people, so they started |
| 118 | using LFSR's whenever they needed to and never looked back. |
| 119 | |
| 120 | Anyway, by the late 60's people who knew how to use slide rules had |
| 121 | realized that using numbers that only *looked* random could really heck |
| 122 | up their math pretty bad, and one of the more common LCG implmentations, |
| 123 | RANDU, was actually about as bad as possible. So, just using any old |
| 124 | LCG wasn't good enough, you had to use one made by someone with a PhD in |
| 125 | mathematics. Donald Knuth shook his fist at the world and shouted "Hah! |
| 126 | I told you so!", published a book on how to do it Right that most people |
| 127 | didn't read, and then went back into his Fortress of Solitude to write |
| 128 | TeX. Because it was created by IBM, RANDU's awfulness is now enshrined |
| 129 | forever in history documents like this one, and because the people |
| 130 | writing OS's and programming languages at the time weren't actually |
| 131 | doing much slide-rule stuff anymore and didn't actually *need* very good |
| 132 | random-looking numbers, everyone went back to using whatever old crap |
| 133 | RNG they were using anyway. The problem was solved, or at least not |
| 134 | terribly problematic, and life was good. |
| 135 | |
| 136 | Also, sometime in the 70's or 80's the arts of cryptography started |
| 137 | leaking from classified government works into the real world. People |
| 138 | started thinking about how much money they could make from scrambling |
| 139 | satellite TV so that plebs with HAM radio licenses couldn't watch it, |
| 140 | and these people started giving more money to people who had PhD's in |
| 141 | mathematics to figure out how to make this work. It was quickly |
| 142 | determined that neither LCG's nor LFSR's made numbers that were |
| 143 | random-looking enough to really get in the way of someone who knew how |
| 144 | to use a slide rule, and since Edith had long ago retired to a small |
| 145 | beach house in New Jersey, they needed to figure out how to get |
| 146 | computers to make better random-looking numbers. But making numbers |
| 147 | look random enough that someone couldn't undo the process and get free |
| 148 | pay-per-view was slow and involved lots of details that nobody else |
| 149 | really cared about, so that topic went off on its own adventures and |
| 150 | will not be further mentioned. |
| 151 | |
| 152 | Things more or less trundled along this way until the late 90's, when |
| 153 | suddenly computers were everywhere and there was a new generation of |
| 154 | people who had grown up too late to know how to use slide rules, so they |
| 155 | did all their math with computers. They were doing a LOT of math by |
| 156 | now, and they looked around and realized that their random-looking |
| 157 | numbers really weren't very random-looking at all, and this was actually |
| 158 | something of a problem by now. So the Mersenne Twister got invented. |
| 159 | It was pretty slow and used a lot of memory and made kinda mediocre |
| 160 | random numbers, but it was way better than a bad LCG, and most |
| 161 | importantly, it had a cool name. Most people didn't want to read Knuth's |
| 162 | book and figure out how to make a non-bad LCG, so everyone started using |
| 163 | the Mersenne Twister whenever possible. The problem was solved, and |
| 164 | life was good. |
| 165 | |
| 166 | This is where things stood until the early 2010's, when I finished my MS |
| 167 | and started paying attention again. People suddenly realized it was |
| 168 | possible to make random-looking numbers better than the Mersenne Twister |
| 169 | using an algorithm called xorshift. Xorshift was fast, it made good |
| 170 | pretty random-looking numbers, and it didn't need a whole 3 kilobytes of |
| 171 | state just sitting around taking up space and causing comment among the |
| 172 | neighbors at church. It did sometimes have problems with some of its |
| 173 | numbers not looking random enough in a few select circumstances, but |
| 174 | people were gun-shy about their randomness by now so a few people with |
| 175 | PhD's in mathematics slowly and patiently spent years figuring out ways |
| 176 | to work around these problems, leading to a whole confusing family of |
| 177 | related things such as xoshiro, xoroshiro, xoroshiro+, xoroshiro*, and |
| 178 | so on. Nobody else could really tell the difference between them, but |
| 179 | everyone agreed they were better than Mersenne Twister, easier to |
| 180 | implement, and the name was nearly as cool. Many papers were published, |
| 181 | the problem was solved, and life was good. |
| 182 | |
| 183 | However, at about the same time some bright young spark figured out that |
| 184 | it actually wasn't too hard, if you read Knuth's book and thought real |
| 185 | hard about what you were doing, to take the old LCG and hop it up on |
| 186 | cocaine and moon juice. The result got called the Permuted Congruential |
| 187 | Generator, or PCG. This quite miffed the people working on xorshift |
| 188 | generators by being almost as small and fast, and producing |
| 189 | random-looking numbers that satisfied even the people who had learned to |
| 190 | use slide rules for fun in this latter age. It also used xor's and bit |
| 191 | shifts, and that's xorshift's turf, dammit, it's right in the name! |
| 192 | Since nobody had figured out any downsides to PCG's yet, everyone |
| 193 | shrugged and said "might as well just go with that then", and that is |
| 194 | where, as of 2019, the art currently stands. The problem is solved, and |
| 195 | life is good. |
| 196 | |