Entropy
Library
Eightomic PRNG 8
The fastest 8-bit, sequential PRNG versus JSF8 and PCG8.
#include <stdint.h>
struct eightomic_prng_8_s {
uint8_t a;
uint8_t b;
uint8_t c;
uint8_t d;
uint8_t e;
};
uint8_t eightomic_prng_8(struct eightomic_prng_8_s *s) {
s->a += s->d;
s->b = ((s->b << 3) | (s->b >> 5)) + s->c;
s->c += s->e | 1;
s->d = s->b;
s->e += s->a;
return s->e;
}
eightomic_prng_8() is the randomization function that accepts the following argument.
1: s is the struct eightomic_prng_8_s pointer with 4 8-bit unsigned integers s->a, s->b, s->c, s->d and s->e. Each must be initialized with any combination of values.
The return value data type is uint8_t.
It returns the 8-bit unsigned integer pseudorandom number result.
It's still being tested and the full description is in progress.
Eightomic PRNG 16 A
The fastest sequential PRNG versus slower, weaker rand() implementations for 16-bit numbers.
#include <stdint.h>
struct eightomic_prng_16_a_s {
uint32_t a;
uint32_t b;
};
uint16_t eightomic_prng_16_a(struct eightomic_prng_16_a_s *s) {
s->a = ((s->a << 13) | (s->a >> 19)) ^ s->b;
s->b += 1111111;
return s->a;
}
eightomic_prng_16_a() is the randomization function that accepts the following argument.
1: s is the struct eightomic_prng_16_a_s pointer with 2 32-bit unsigned integers s->a and s->b. Each must be initialized with any combination of values including 0.
The return value data type is uint16_t.
It returns the 16-bit unsigned integer pseudorandom number result.
It's the fastest deterministic, sequential PRNG that passes stdin16 PractRand tests up to 8 million randomized 16-bit numbers.
It's faster than rand() in standard C implementations.
Furthermore, a modern implementation of rand() passes PractRand tests up to 512000 randomized numbers, which is 7% of the high-quality randomized numbers that eightomic_prng_16_a() generates.
It's faster than JSF16 and PCG16 using pcg16_fast, but they both have superior statistical test results.
As an alternative, Eightomic PRNG 16 C has 16-bit integers for 16-bit processor compatibility, superior statistical test results and faster speed than both JSF16 and PCG16.
It's faster than all Xoroshiro and Xorshift algorithms, including Xorshift16 "798".
Furthermore, Xorshift16 "798" passes PractRand tests up to 64000 randomized numbers, which is less than 1% of the high-quality randomized numbers that eightomic_prng_16_a() generates.
Furthermore, some of the compared PRNGs are vulnerable to several confirmed broken cycles when seeded with specific values, including 0.
Eightomic PRNG 16 B
The fastest 16-bit, sequential PRNG versus Xorshift16 "798".
It's not ready yet.
Eightomic PRNG 16 C
The fastest 16-bit, sequential PRNG versus JSF16 and PCG16.
#include <stdint.h>
struct eightomic_prng_16_c_s {
uint16_t a;
uint16_t b;
uint16_t c;
uint16_t d;
uint16_t e;
};
uint16_t eightomic_prng_16_c(struct eightomic_prng_16_c_s *s) {
s->a += s->d;
s->b = ((s->b << 6) | (s->b >> 10)) + s->c;
s->c += s->e;
s->d = s->b;
s->e -= s->a + 1;
return s->c;
}
eightomic_prng_16_c() is the randomization function that accepts the following argument.
1: s is the struct eightomic_prng_16_c_s pointer with 4 16-bit unsigned integers s->a, s->b, s->c, s->d and s->e. Each must be initialized with any combination of values.
The return value data type is uint16_t.
It returns the 16-bit unsigned integer pseudorandom number result.
It's still being tested and the full description is in progress.
Eightomic PRNG 32 A
The fastest 32-bit, sequential PRNG versus Xorshift32.
#include <stdint.h>
struct eightomic_prng_32_a_s {
uint32_t a;
uint32_t b;
};
uint32_t eightomic_prng_32_a(struct eightomic_prng_32_a_s *s) {
s->a = ((s->a << 22) | (s->a >> 10)) ^ s->b;
s->b += 1111111111;
return s->a + s->b;
}
eightomic_prng_32_a() is the randomization function that accepts the following argument.
1: s is the struct eightomic_prng_32_a_s pointer with 2 32-bit unsigned integers s->a and s->b. Each must be initialized with any combination of values.
The return value data type is uint32_t.
It returns the 32-bit unsigned integer pseudorandom number result.
It's still being tested and the full description is in progress.
Eightomic PRNG 32 B
The fastest 32-bit, sequential PRNG versus JSF32 and PCG32.
#include <stdint.h>
struct eightomic_prng_32_b_s {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
uint32_t e;
};
uint32_t eightomic_prng_32_b(struct eightomic_prng_32_b_s *s) {
s->a += s->d;
s->b = ((s->b << 19) | (s->b >> 13)) ^ s->c;
s->e -= 111111;
s->c -= s->e;
s->d += s->b;
return s->a;
}
eightomic_prng_32_b() is the randomization function that accepts the following argument.
1: s is the struct eightomic_prng_32_b_s pointer with 4 uint32_t integers s->a, s->b, s->c, s->d and s->e. Each must be initialized with any combination of values.
The return value data type is uint32_t.
It returns the 32-bit unsigned integer pseudorandom number result.
It has an estimated full cycle of 2⁶⁴ numbers.
The following test results are performed with all state bits initialized to 0.
It passes Diehard tests.
It's likely to pass Practrand tests, but the results are pending.
It passes all TestU01 BigCrush tests as the fastest sequential PRNG that passes BigCrush.
It's compared to the fastest 32-bit PRNGs that generate one random number per function call as required in most practical instances.
It's faster than JSF32.
It's faster than PCG32 using pcg32_fast.
It's faster than Lehmer.
It's faster than all Xoroshiro and Xorshift algorithms.
Furthermore, most of these PRNGs are vulnerable to several confirmed broken cycles when seeded with specific values, including 0.
When only 16-bit numbers are required, Eightomic PRNG 16 A is the fastest 16-bit PRNG with good diffusion.
When a longer full cycle is required for 32-bit numbers, Eightomic PRNG 32 C is a high-quality, long-period PRNG with flexible state sizes and similar speed to Xorshift32.
Eightomic PRNG 32 C
The fastest 32-bit, long-period, sequential PRNG versus 32-Bit SIMD Mersenne Twister.
#include <stdint.h>
struct eightomic_prng_32_c_s {
uint32_t blocks[1024];
uint32_t blocks_selector;
uint32_t increment;
uint32_t increment_offset;
};
uint32_t eightomic_prng_32_c(struct eightomic_prng_32_c_s *s) {
uint32_t block = s->blocks[s->blocks_selector & 1023];
const uint32_t increment_offset_capture = s->increment_offset ^ s->increment;
s->blocks[s->blocks_selector & 1023] += increment_offset_capture;
s->increment_offset = ((s->increment_offset << 17)
| (s->increment_offset >> 15)) + s->increment;
s->increment += 1111111111;
s->blocks_selector++;
block += s->increment + increment_offset_capture;
s->blocks[block & 1023] += s->blocks_selector + block;
return block;
}
eightomic_prng_32_c() is the randomization function that accepts the following argument.
1: s is the struct eightomic_prng_32_c_s pointer with 3 uint32_t integers s->a, s->b and s->increment. Each must be initialized with any combination of values.
The return value data type is uint32_t.
It returns the 32-bit unsigned integer pseudorandom number result.
It has a long period that's adjustable to any halved amount by adjusting the 1024 state blocks, meaning the additional possible state sizes are 512, 256, 128, 64, 32, 16, 8, 4 and 2.
If the count of blocks is adjusted, the & 1023 mask instances must be adjusted accordingly. These varying state sizes may result in better or worse statistical quality by a small margin.
The estimated full cycle is 2³²⁷⁶⁸ numbers, so re-seeding the initial state isn't required in most applications.
Furthermore, when all state bits are 0, the next pseudorandom number escapes zeroland quickly, making it impossible to have a broken state with any combination of numbers.
A round-robin number selector is incremented before assigning an additive XOR state to the selected s->blocks number, ensuring the closest thing to equal distribution across all possible cycles.
All state variable assignments are additive to emulate the properties of minimal rolling hash functions and avoid broken cycles.
After 4294967295 random numbers are generated, the aforementioned 32 bits of state in s->increment completes a full cycle and the s->blocks bits avoid a full cycle, as demonstrated in the first 10 instances with the following code example.
#include <stdio.h>
#include "eightomic_prng_32_c.h"
int main(void) {
struct eightomic_prng_32_c_s s;
uint32_t increment_capture;
unsigned long i = 0;
while (i < 1024) {
s.blocks[i] = 0;
i++;
}
s.blocks_selector = 0;
s.increment = 0;
s.increment_offset = 0;
i = 0;
while (i < 10) {
eightomic_prng_32_c(&s);
increment_capture = s.increment;
eightomic_prng_32_c(&s);
while (s.increment != increment_capture) {
eightomic_prng_32_c(&s);
}
printf("%10lu %10lu %10lu %10lu %10lu %10lu %10lu %10lu\n",
s.blocks[0], s.blocks[1], s.blocks[2], s.blocks[3],
s.blocks[4], s.blocks[5], s.blocks[6], s.blocks[7]);
i++;
}
}
The output demonstrates a visual confirmation of good distribution among each block in s->blocks after each full cycle of s->increment.
A wrapping additive constant added to each state block isn't enough to ensure a 2³²⁷⁶⁸ full cycle, so each previous state block value is used as an offset to assign a combined pseudorandom value to a secondary state block.
The following code example demonstrates good distribution across s->blocks instead of brute-forcing millions of statistical tests.
#include <stdint.h>
#include <stdio.h>
struct eightomic_prng_32_c_s {
uint32_t blocks[1024];
uint32_t blocks_offset_assignment_counts[1024];
uint32_t blocks_selector;
uint32_t increment;
uint32_t increment_offset;
};
uint32_t eightomic_prng_32_c(struct eightomic_prng_32_c_s *s) {
uint32_t block = s->blocks[s->blocks_selector & 1023];
const uint32_t increment_offset_capture = s->increment_offset ^ s->increment;
s->blocks[s->blocks_selector & 1023] += increment_offset_capture;
s->increment_offset = ((s->increment_offset << 17)
| (s->increment_offset >> 15)) + s->increment;
s->increment += 1111111111;
s->blocks_selector++;
block += s->increment + increment_offset_capture;
s->blocks[block & 1023] += s->blocks_selector + block;
s->blocks_offset_assignment_counts[block & 1023]++;
return block;
}
int main(void) {
struct eightomic_prng_32_c_s s;
unsigned char blocks_offset_assignment_duplicate_states[1024];
unsigned long blocks_offset_assignment_duplicates_count = 0;
unsigned long i = 0;
unsigned short j = 0;
while (i < 1024) {
s.blocks[i] = 0;
s.blocks_offset_assignment_counts[i] = 0;
blocks_offset_assignment_duplicate_states[i] = 0;
i++;
}
s.blocks_selector = 0;
s.increment = 0;
s.increment_offset = 0;
while (i < 1111111111) {
eightomic_prng_32_c(&s);
i++;
}
i = 0;
while (i < 1024) {
j = 0;
while (j < 1024) {
if (
i != j &&
s.blocks_offset_assignment_counts[i]
== s.blocks_offset_assignment_counts[j] &&
blocks_offset_assignment_duplicate_states[i] != 1
) {
blocks_offset_assignment_duplicate_states[j] = 1;
blocks_offset_assignment_duplicates_count++;
}
j++;
}
i++;
}
i = 0;
while (i < 1024) {
printf("Block %lu is assigned by an offset %lu times.\n",
i + 1,
s.blocks_offset_assignment_counts[i]);
i++;
}
printf("\nThere are %lu duplicate offset block assignments.\n",
blocks_offset_assignment_duplicates_count);
return 0;
}
The offset assignment counts demonstrate semi-linear, yet semi-randomized offset assignments distributed throughout the state in s->blocks.
Furthermore, there are 145 colliding offset block increments in the aforementioned instance out of 1024 total blocks.
As the count of generated numbers increases, the number of blocks with the same amount of offset increments decreases.
For example, there are 93 collisions after generating 2222222222 numbers, then 78 collisions after generating 3333333333 numbers.
The following test results are performed with all state bits initialized to 0.
Practrand test results are currently pending, although it's likely to pass beyond the default 32 TB limit.
It passes all TestU01 BigCrush tests as the fastest long-period Mersenne Twister alternative that passes BigCrush.
When initializing using 1024 random TRNG numbers manually assigned to s->blocks, the results are similar with between 98% to 100% of BigCrush tests passed consistently due to the proven distribution properties.
Furthermore, 32-bit Mersenne Twister is known to exhibit multiple consistent 32-bit test failures with small and large random number tests.
It's faster than MRG32k3a, 32-bit SIMD Mersenne Twister, WELL, Xoroshiro and Xorshift algorithms.
Furthermore, most of these compared PRNGs are vulnerable to several confirmed broken cycles when seeded with specific values, including 0.
When efficient memory usage and faster speed are required for 32-bit PRNG usage within a large number of processes, Eightomic PRNG 32 B is the fastest 32-bit sequential PRNG that passes BigCrush tests with a short period.
Eightomic PRNG 64 A
The fastest 64-bit, sequential PRNG versus Xorshift64.
Eightomic PRNG 64 B
The fastest 64-bit, sequential PRNG versus JSF64, PCG64 and Xorshift128+.
It's not ready yet.
Eightomic PRNG 64 C
The fastest 32-bit, long-period, sequential PRNG versus 64-bit SIMD Mersenne Twister.
It's not ready yet.
License
Eightomic License
© Eightomic <https://eightomic.com>
Permission to both copy this software and use copies of this software is
granted only when the following 2 conditions are satisfied.
1. These software license conditions in entirety, both unmodified and without
obfuscation, must be included wherever an instance of either a copy of this
software or a derivation from a copy of this software is implemented.
2. Liability for damages incurred in conjunction with this software must not
be assumed by Eightomic.