The design

The idea behind this exceedingly simple algorithm is inspired by the simplicity of the Mersenne twister. The basic design philosophy of the mersenne twister is that it’s based on a large array of pre-computed “really random” numbers. This works as a large source of entropy to feed to some other algorithm(In particular, a Linear Congruential Generator) so that you don’t have to rely on the entropy from the single number fed to it as a seed.

Stealing that basic premise, but not using a linear congruential generator, my idea was the following:

  1. Take the seed as state(Called input), and keep an index in state as 0 (Called Index). Let arr be a pre-computed list of random numbers
  2. input = input xor arr[index]
  3. ROL or ROR input arr[index] by *input
  4. arr[index] = input
  5. index = input % len arr (If it’s a power of two, you only need a bitmask. This is probably how it’ll actually be implemented)
  6. jump to 2, until satisfied with # iterations

Some questions:

  1. How well does this work as a random number generator (GIven the output at the end is input). Could you test and analyse the algorithm and get a semi-definitive answer?
  2. How efficient would this be in terms of speed? Would this be slower than the mersenne twister?
  3. What are some ways to improve this without making it much more complicated? I was considering having the ROL after storing input, instead of before, but I thought that might end up limiting entropy because of how the operations worked. Here are the results of the dieharder tests applied to this algorithm. All in all, for my first attempt at prng, I think it did pretty well:
test_namentuptsamplespsamplespvalueassessment
diehard_birthdays01001000.98356356PASSED
diehard_operm5010000001000.58750898PASSED
diehard_rank_32x320400001000.49593991PASSED
diehard_rank_6x801000001000.97122000PASSED
diehard_bitstream020971521000.87549025PASSED
diehard_opso020971521000.69945561PASSED
diehard_oqso020971521000.55905649PASSED
diehard_dna020971521000.65120873PASSED
diehard_count_1s_str02560001000.48734833PASSED
diehard_count_1s_byt02560001000.59092515PASSED
diehard_parking_lot0120001000.35536156PASSED
diehard_2dsphere280001000.74794961PASSED
diehard_3dsphere340001000.22163148PASSED
diehard_squeeze01000001000.75768713PASSED
diehard_sums01001000.36175030PASSED
diehard_runs01000001000.77452905PASSED
diehard_runs01000001000.72743300PASSED
diehard_craps02000001000.66498955PASSED
diehard_craps02000001000.64124851PASSED
marsaglia_tsang_gcd0100000001000.00000079FAILED
marsaglia_tsang_gcd0100000001000.02876877PASSED
sts_monobit11000001000.28733001PASSED
sts_runs21000001000.97313221PASSED
sts_serial11000001000.79560756PASSED
sts_serial21000001000.50918839PASSED
sts_serial31000001000.72861109PASSED
sts_serial31000001000.76609771PASSED
sts_serial41000001000.35115125PASSED
sts_serial41000001000.75720281PASSED
sts_serial51000001000.34961276PASSED
sts_serial51000001000.66295337PASSED
sts_serial61000001000.26082606PASSED
sts_serial61000001000.44561287PASSED
sts_serial71000001000.09372991PASSED
sts_serial71000001000.26405456PASSED
sts_serial81000001000.24357032PASSED
sts_serial81000001000.64314616PASSED
sts_serial91000001000.96798350PASSED
sts_serial91000001000.29572749PASSED
sts_serial101000001000.62468883PASSED
sts_serial101000001000.92104178PASSED
sts_serial111000001000.96622038PASSED
sts_serial111000001000.56325088PASSED
sts_serial121000001000.84488898PASSED
sts_serial121000001000.89353988PASSED
sts_serial131000001000.70215000PASSED
sts_serial131000001000.41082605PASSED
sts_serial141000001000.66789572PASSED
sts_serial141000001000.63501686PASSED
sts_serial151000001000.97273385PASSED
sts_serial151000001000.41314752PASSED
sts_serial161000001000.77008188PASSED
sts_serial161000001000.46351042PASSED
rgb_bitdist11000001000.55039110PASSED
rgb_bitdist21000001000.69463258PASSED
rgb_bitdist31000001000.53884696PASSED
rgb_bitdist41000001000.96176534PASSED
rgb_bitdist51000001000.84241668PASSED
rgb_bitdist61000001000.89273771PASSED
rgb_bitdist71000001000.27869261PASSED
rgb_bitdist81000001000.99910785WEAK
rgb_bitdist91000001000.61862080PASSED
rgb_bitdist101000001000.49293572PASSED
rgb_bitdist111000001000.19763570PASSED
rgb_bitdist121000001000.99748606WEAK
rgb_minimum_distance21000010000.27917753PASSED
rgb_minimum_distance31000010000.26740171PASSED
rgb_minimum_distance41000010000.64313190PASSED
rgb_minimum_distance51000010000.03399061PASSED
rgb_permutations21000001000.06407396PASSED
rgb_permutations31000001000.23247355PASSED
rgb_permutations41000001000.84328723PASSED
rgb_permutations51000001000.96563949PASSED
rgb_lagged_sum010000001000.96738945PASSED
rgb_lagged_sum110000001000.80570241PASSED
rgb_lagged_sum210000001000.73346401PASSED
rgb_lagged_sum310000001000.17319405PASSED
rgb_lagged_sum410000001000.66984255PASSED
rgb_lagged_sum510000001000.93320792PASSED
rgb_lagged_sum610000001000.48806544PASSED
rgb_lagged_sum710000001000.02161892PASSED
rgb_lagged_sum810000001000.56950881PASSED
rgb_lagged_sum910000001000.70158921PASSED
rgb_lagged_sum1010000001000.36567836PASSED
rgb_lagged_sum1110000001000.05397063PASSED
rgb_lagged_sum1210000001000.84515823PASSED
rgb_lagged_sum1310000001000.34851872PASSED
rgb_lagged_sum1410000001000.00595100PASSED
rgb_lagged_sum1510000001000.00659663PASSED
rgb_lagged_sum1610000001000.91978909PASSED
rgb_lagged_sum1710000001000.60627753PASSED
rgb_lagged_sum1810000001000.99545301WEAK
rgb_lagged_sum1910000001000.00415340WEAK
rgb_lagged_sum2010000001000.59316496PASSED
rgb_lagged_sum2110000001000.95138572PASSED
rgb_lagged_sum2210000001000.66672474PASSED
rgb_lagged_sum2310000001000.00159695WEAK
rgb_lagged_sum2410000001000.87339649PASSED
rgb_lagged_sum2510000001000.56168925PASSED
rgb_lagged_sum2610000001000.85981205PASSED
rgb_lagged_sum2710000001000.17565003PASSED
rgb_lagged_sum2810000001000.42078003PASSED
rgb_lagged_sum2910000001000.01033951PASSED
rgb_lagged_sum3010000001000.40451497PASSED
rgb_lagged_sum3110000001000.00000190WEAK
rgb_lagged_sum3210000001000.22031260PASSED
rgb_kstest_test01000010000.35700639PASSED
dab_bytedistrib05120000010.00000000FAILED
dab_dct2565000010.91065627PASSED
dab_filltree321500000010.92374295PASSED
dab_filltree321500000010.95349424PASSED
dab_filltree20500000010.76532971PASSED
dab_filltree21500000010.97301100PASSED
dab_monobit2126500000010.62278368PASSED

An interesting result from dab_bytedistrib. 0.000000, huh? The fact that this gives good results(At least, in other areas) tells me that it’s properly taking advantage of the entropy from the small array; these are the results from an array of just 128 64-bit numbers. If it can do this well with so little entropy compared to the samples the test takes, it should mean it’s pretty solid.

One improvement I made was to ROL based on the previous number(Or 0 if no previous number) rather than by the current one. This seemed to break small cycles a lot better for some reason.