This commit is contained in:
Miloslav Ciz 2024-05-28 21:17:58 +02:00
parent 6b6fe66cd4
commit 6e8181c3e8
7 changed files with 1799 additions and 1786 deletions

View file

@ -45,7 +45,7 @@ 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. `C` is the multiplicative constant, `A` 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:
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 |
| ------------- | ------------------- | --------- | -------- | -------------------- |
@ -56,11 +56,11 @@ Here `T` is the data type of the internal number (implying the *M* constant) --
| `uint64_t` | 2862933555777941757 | 12345 | 32 or 48 | *A* from *L'Ecuyer* |
| `uint64_t` | 3935559000370003845 | 1719 | 32 or 48 | *A* from *L'Ecuyer* |
{ 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. ~drummyfish }
{ 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 }
Let's also quickly mention **another kind of generator** as an alternative -- the *middle square plus Weyl sequence* generator. Middle square generator was one of the first and is very simple, it simply starts with a number (seed), squares it, takes its middle digits as the next number, squares it, takes its middle digits and so on. The issue with this was mainly getting a number 0, at which we get stuck. A 2022 paper by *Wydinski* seems to have solved this issue by employing so called *Weyl* sequence -- basically just adding some odd number in each step, though the theory is a bit more complex, the paper goes on to prove a high period of this generator. An issue seems to be with seeding the sequence -- the generator has three internal numbers and they can't just be blindly set to "anything" (the paper gives some hints on how to do this). Here is a 32 bit variant of such generator (the paper gives a 64 bit one):
{ I tried to make a 32 bit version of the generator, tried to choose the `_rand3` constant well -- after quickly testing this the values of the generator looked alright, though I just eyeballed the numbers, each bit separately, checked the mean of some 4000 values and the histogram of 1 million values. I'm not claiming this version to be statistically good, but it may be a start for implementing something nice, use at own risk. ~drummyfish }
{ I tried to make a 32 bit version of the generator, tried to choose the `_rand3` constant well -- after quickly testing this the values of the generator looked alright, though I just mostly eyeballed the numbers, each bit separately, checked the mean of some 4000 values and the histogram of 1 million values. I also ran this through ent and it gave good results except for the chi square test that reported the rarity of the sequence at something over 5% (i.e. not impossible, but something like 1 in 20 chance). I'm not claiming this version to be statistically good, but it may be a start for implementing something nice, use at own risk. ~drummyfish }
```
#include <stdint.h>
@ -79,7 +79,7 @@ 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.
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. ~drummyfish }
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 }
```
#include <stdint.h>