Update
This commit is contained in:
parent
a62675cb93
commit
a64b3eb7a9
19 changed files with 1978 additions and 1966 deletions
|
@ -49,14 +49,14 @@ unsigned int random()
|
|||
|
||||
Here `T` is the data type of the internal number (implying the *M* constant) -- use some fixed width type from `stdint.h` here. `A` is the multiplicative constant, `C` is the additive constant and `S` is a shift that implies how many highest bits of the internal number will be taken (and therefore what range of numbers we'll be getting). The following table gives you a few hopefully good values you can just plug into this snippet to get an alright generator:
|
||||
|
||||
| `T` | `A` | `C` | `S` | note |
|
||||
| ------------- | ------------------- | --------- | -------- | -------------------- |
|
||||
| `uint32_t` | 32310901 | 37 | 16 or 24 | *A* from *L'Ecuyer* |
|
||||
| `uint32_t` | 2891336453 | 123 | 16 or 24 | *A* from *L'Ecuyer* |
|
||||
| `uint32_t` | 2147001325 | 715136305 | 16 | from *Entacher 1999* |
|
||||
| `uint32_t` | 22695477 | 1 | 16 | from *Entacher 1999* |
|
||||
| `uint64_t` | 2862933555777941757 | 12345 | 32 or 48 | *A* from *L'Ecuyer* |
|
||||
| `uint64_t` | 3935559000370003845 | 1719 | 32 or 48 | *A* from *L'Ecuyer* |
|
||||
| `T` | `A` | `C` | `S` | note | sequence sample (starting from 100th number) |
|
||||
| ------------- | ------------------- | --------- | -------- | -------------------- | ------------------------------------------------------------------------- |
|
||||
| `uint32_t` | 32310901 | 37 | 16 or 24 | *A* from *L'Ecuyer* | 38118, 197, 28170, 11612, 21102, 63207, 2572, 21309, 59711, 17284, ... |
|
||||
| `uint32_t` | 2891336453 | 123 | 16 or 24 | *A* from *L'Ecuyer* | 31804, 54678, 21911, 47965, 33591, 23969, 38804, 659, 5011, 43707, ... |
|
||||
| `uint32_t` | 2147001325 | 715136305 | 16 | from *Entacher 1999* | 40401, 62120, 18120, 47981, 63951, 61090, 35627, 51189, 49566, 13666, ... |
|
||||
| `uint32_t` | 22695477 | 1 | 16 | from *Entacher 1999* | 61458, 34169, 50905, 16735, 20343, 25267, 41080, 39879, 40501, 10993, ... |
|
||||
| `uint64_t` | 2862933555777941757 | 12345 | 32 or 48 | *A* from *L'Ecuyer* | 2204069570, 3565223070, 71446738, 528880356, 4046402086, 3687091948, ... |
|
||||
| `uint64_t` | 3935559000370003845 | 1719 | 32 or 48 | *A* from *L'Ecuyer* | 3897855749, 430815323, 2783259848, 156663604, 2365550848, 2624048926, ... |
|
||||
|
||||
{ I pulled the above numbers from various sources I found, mentioned in the note, tried to select the ones that were allegedly good, I also quickly tested them myself, checked the period was at maximum at least for the 32 bit generators and lower and ran it through ent which reported good results. ~drummyfish }
|
||||
|
||||
|
@ -81,6 +81,8 @@ uint16_t random()
|
|||
|
||||
NOTE on the code: the `(_rand1 >> 16) | (_rand1 << 16)` operation effectively makes the function return lower 16 bits of the squared number's middle digits, as multiplying `_rand1` (32 bit) by itself results in the lower half of a 64 bit result.
|
||||
|
||||
The obtained sequence starts as: 24089, 36550, 36617, 6030, 11432, 62341, 37282, 32467, 23029, 26116, 63979, 36493, ...
|
||||
|
||||
Yet another idea might be to use some good [hash](hash.md) just on numbers 1, 2, 3, 4 ... The difference here is we are not computing the pseudorandom number from the previous one, but we're computing *N*th pseudorandom number directly from *N*. This will probably be slower. For example: { Again, no big guarantees, but I ran this through ent again and got very good results. ~drummyfish }
|
||||
|
||||
```
|
||||
|
@ -105,6 +107,8 @@ void randomSeed(uint32_t seed)
|
|||
}
|
||||
```
|
||||
|
||||
This generates a sequence starting with: 0, 3768839452, 4227911003, 1223184510, 4160985782, 2003897881, 3431987483, 2357500583, 4026873197, 1007578691, 698404316, 753669850, ...
|
||||
|
||||
**How to generate a number in certain desired range?** As said your generator will be giving you numbers of certain fixed number of bits, usually something like 16 or 32, which means you'll be getting numbers in range 0 to 2^bits - 1. But what if you want to get numbers in some specific range *A* to *B* (including both)? To do this you just need to generate a number in range 0 to *B - A* and then add *A* to it (e.g. to generate number from 20 to 30 you generate a number from 0 to 10 and add 20). So let's just suppose we want a number in range 0 to *N* (where *N* can be *B - A*). Let's now suppose *N* is lower than the upper range of our generator, i.e. that we want to get the number into a small range (if this is not the case, we can arbitrarily increase the range of our generator simply by generating more random bits with it, i.e we can join two 16 bit numbers to get a 32 bit number etc.). Now the most common way to get the number in the desired range is by using *modulo (N + 1)* operation, i.e. in [C](c.md) we simply do something like `int random0to100 = random() % 101;`. This easily forces the number we get into the range we want. HOWEVER beware, there is one statistical trap about this called the **modulo bias** that makes some numbers slightly more likely to be generated than others, i.e. it biases our distribution a little bit. For example imagine our generator gives us numbers from 0 to 15 and we want to turn it into range 0 to 10 using the modulo operator, i.e. we'll be doing *mod 11* operation -- there are two ways to get 0 (*0 mod 11* and *11 mod 11*) but only one way to get 9 (*9 mod 11*), so number 0 is twice as likely here. In practice this effect isn't so strong and in many situations we don't really mind it, but we have to be aware of this effects for the sake of cases where it may matter. If necessary, the effect can be reduced -- we may for example realize that modulo bias will be eliminated if the upper range of our generator is a multiple of the range into which we'll be converting, so we can just repeatedly generate numbers until it falls under a limit that's a highest multiple of our desired range lower than the true range of the generator.
|
||||
|
||||
**What if we want [floating point](float.md)/[fixed point](fixed_point.md) numbers?** Just convert the integer result to that format somehow, for example `((float) random()) / ((float) RANDOM_MAX_VALUE)` will produce a floating point number in range 0 to 1.
|
||||
|
@ -151,4 +155,4 @@ However the core of a pseudorandom generator is the quality of the sequence itse
|
|||
- [pseudo](pseudo.md)
|
||||
- [randomness](randomness.md)
|
||||
- [noise](noise.md)
|
||||
- [bytebeat](bytebeat.md)
|
||||
- [bytebeat](bytebeat.md)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue