Shop OBEX P1 Docs P2 Docs Learn Events
Random/LFSR on P2 - Page 70 — Parallax Forums

Random/LFSR on P2

1676870727392

Comments

  • evanhevanh Posts: 15,126
    5. [Edit] Each A,B,C,D,M,E stream will have similar statistical properties to the base A,B,C,D stream (to do: characterize the extents of statistical variation with various M,E).
    Are you thinking this could be improved within the restrictive confines we're working under?
  • xoroshironotxoroshironot Posts: 309
    edited 2019-04-08 01:12
    evanh wrote: »
    5. [Edit] Each A,B,C,D,M,E stream will have similar statistical properties to the base A,B,C,D stream (to do: characterize the extents of statistical variation with various M,E).
    Are you thinking this could be improved within the restrictive confines we're working under?
    Yes, to some extent... try a dozen or so random/arbitrary 16-bit values for M (replacing 0xFFFF) with 13,5,10,9,E; calculating E using your exhaustive search code with M in effect. Edit: ... calculating BS from the table in the following post, and then E from BS, both with M in effect.
    If you find a value for M that is statistically superior, great, then you could modify the seeder, engine and scrambler to use BS, M and E, respectively.

    If you find all values of (M,E) are statistically similar, then consider whether there is room to apply M and E as a replaceable parameters, perhaps adjustable by the end user:
    Could the P2 support replaceable parameters for M and E within the engine and scrambler?... if so:
    1. User/Firmware may pick M (starting with 0, for default P2 behavior) and store it.
    2. Firmware will (hopefully be able to) calculate BS from M and use it to verify any current/new seed is valid (i.e. seed <> BS), adding 1, if not.
    3. Firmware will automatically calculate E from BS and store it (again, starting with 0, for default P2 behavior).
    4. (Optional) User may override firmware calculated E (e.g. to create a stream with an equal number of 1 and 0 bits in the entire period).

    I am working on calculating BS directly from M.

    However if there were no constraint on automatically supplying an E that restores the single short output value of the full period to a zero, then BS could eliminated as well:
    1. Generate an arbitrary 32-bit seed.
    2. Choose any value for M.
    3. Run a single iteration of xoroshiro and then compare the state to the original seed from step 1.
    4. If the state is equal to the original seed, add 1 to the state.
  • xoroshironotxoroshironot Posts: 309
    edited 2019-04-07 22:32
    I am working on calculating BS directly from M.
    This table is usable for directly calculating BS from M on 13,5,10,9 (and then E from BS and D):
    BS lookup table for 13,5,10
    Bit0: 0x105A06DE
    Bit1: 0x30EE0B62 
    Bit2: 0x61DC16C4
    Bit3: 0xD3E22B56
    Bit4: 0x6D75302E
    Bit5: 0xCAB06682
    Bit6: 0x4F8BAD58
    Bit7: 0x55A63C33
    Bit8: 0xAB4C7866
    Bit9: 0x9C29964E
    Bit10: 0x38532C9D
    Bit11: 0x60FC5FE4
    Bit12: 0xD1A2B916
    Bit13: 0xA345722D
    Bit14: 0x8C3B82D8
    Bit15: 0x082D036F
    
    For example, suppose I pick an arbitrary M=21 (0x15).
    Therefore bits 0, 2 and 4 are set.
    So we xor the table values for those 3 set bits together: BS = 0x105A06DE ^ 0x61DC16C4 ^ 0x6D75302E = 0x1CF32034
    Thus BS0=0x2034 and BS1=0x1CF3.
    Now we calculate E from BS and D : E = 0x2034 + ROL(0x2034 + 0x1CF3, 9) = 0x6EAE
    Finally, we ensure the current state <> BS: If (state==BS) {state++;}

    The BS table values were generated by passing A=13,B=5,C=10 with each of the 16 single-bit set values for M to my original brute force search algorithm which returns BS, but modified to receive M (instead of only using 0xFFFF).

    Edit: Fixed a lookup/math error when manually calculating BS and E in the example.
    Edit2: Obviously a better way to calculate BS directly from M would be required for implementing this on larger state versions of xoroshiro... but only in order to restore the missing zero to the output, which would be kind of pointless for a larger state generator. Otherwise, just ensure 1 iteration does not return the same state as the seed.
  • evanhevanh Posts: 15,126
    If you find a value for M that is statistically superior, great, then you could modify the seeder, engine and scrambler to use BS, M and E, respectively.
    I did a Practrand gridding run last night. It took about 5 hours to produce 1900 scores. Being a grid run, the average score is higher than a plain full-width sampling aperture. So 400 scores per hour should be possible for ungridded singles. This is an 8-core 4 GHz CPU.

    84 x 15 x 65534 = 82572840 test cases to run. At 400/hr comes to about 23.5 years to run.

  • evanhevanh Posts: 15,126
    If you find all values of (M,E) are statistically similar, then consider whether there is room to apply M and E as a replaceable parameters, perhaps adjustable by the end user:
    Aside from the fact that that isn't an option due to enormous increase in hardware requirements, so far there isn't any real sign of a measurable improvement over the existing Xoroshiro32++. If anything is found, it'll either be fixed constants ... or can only usefully be a software oriented solution.

    The moment a function has adjustable parameters it incurs hardware cost. Simple logic is least costly but even that still needs parameter store register. A barrel shifter is a great example of a costly function. If it has a constant shift parameter then it is 0% logic and 0% store cost. Only costs a little routing. But the moment the shift parameter becomes adjustable you have a small parameter register plus a huge mass of logic to mux each bit of the input data to selectively all bits of the output data. And the routing bloats out with that.
  • evanhevanh Posts: 15,126
    edited 2019-04-08 02:10
    evanh wrote: »
    Aside from the fact that that isn't an option due to enormous increase in hardware requirements
    Heh, apologies, that was a tad harsh. All that's needed is two parameter registers for an xor and adder. In both cases the logic doesn't change in size so it's not a huge increase at all. But even those extra registers have to be worthy. The quality improvement would need to be significant, as in reaching up to the 8 GB mark.
  • xoroshironotxoroshironot Posts: 309
    edited 2019-04-08 02:10
    evanh wrote: »
    84 x 15 x 65534 = 82572840 test cases to run. At 400/hr comes to about 23.5 years to run.
    84 triplets... likely only 5-10 of the candidates from your original testing (that eventually settled on 13,5,10,9) would be required. Other candidates should still fail scrutiny with any value of M.
    15 D rotations... D = 1,2,14 and 15 have little chance to make the grade in my testing on several candidates, but automating all 15 is fine.
    65534 M values (as 0 and ffff were tested)... only a few dozen should be required for each ABCD to decide which few candidates to focus on.

    Once a few ABCD candidates are chosen, then 1 week for each to find the best M at 400/hr... or stop short, as it is unlikely that the best randomly chosen M of 1000 will be significantly better that the best of 65536.
    Take the best ABCD from those few.

    If all M for the best ABCD candidate look good within statistical reason, that would be evidence to allow M to be user programmable (if that were possible). Otherwise, use the best M found.

    On a related note... if for some reason you think that the engine cannot handle the extra ^ M term... it could be moved to the last line: s[1] = rotl(s1 ^ M, C);
    However, that would take me back to the beginning on double-checking basic statistics, verifying de-correlation of parallel streams, and solving for BS, etc.
    If I release code for 128-bit state xoroshiro, it will likely have that change made, but only if all looks good at 32-bit state.
  • evanhevanh Posts: 15,126
    edited 2019-04-08 02:26
    Once a few ABCD candidates are chosen, then 1 week for each to find the best ...
    Holly molly! Here I was thinking I was explaining the ridiculous nature of that approach. O_o

    Tony can vouch for my ability to keep the computer on for more than a couple of days at a time.
  • evanh wrote: »
    The quality improvement would need to be significant, as in reaching up to the 8 GB mark.
    The only ways that could happen would be:
    1. Break equidistribution (e.g. 'scro-rarns')
    2. Increase state size.
    3. Xor the output of two good 32-bit prngs (which is basically an inferior version of #2).

    If you shuffled all output values from one full period and fed them into PractRand, it would likely fail at 2GB, but still probably 1GB.
    At best, I was hoping to find an ABCDEM candidate that would consistently make it to >= 1GB on all apertures (or whatever criteria makes sense for a measured improvement).
    If you find one, that would be awesome.

    For my part, I'm very pleased to have stumbled on a viable mechanism for spawning de-correlated xoroshiro128 streams that benchmark about 90% as fast as the original.
  • evanhevanh Posts: 15,126
    Chris,
    I can hand over all my sources if you like. The automation is all done with Bash scripts though. And it's an evolving beast, every day some changes are made. The useful parts in C are mostly the reconfigurable enhancements on the basic algorithms.
  • evanhevanh Posts: 15,126
    If you shuffled all output values from one full period and fed them into PractRand, it would likely fail at 2GB, but still probably 1GB.
    I didn't have a clue. So that's the nature of equidistribution then. Which I know we want to keep.
  • evanh wrote: »
    Tony can vouch for my ability to keep the computer on for more than a couple of days at a time.
    I have 6 + 16 cores (two workstations) so 44 threads... and that is not always enough.
    I sometimes still have to reach out to a friend (who is 'off-the-grid', so to speak) for his additional 24 threads for weeks at a time.

    Sometimes I envy those crypto-jackers for having been able to bring to bear a huge amount of parallel processing power through unaware web-browsers.
    Some of my years long calculation ideas would be done in hours.
  • evanh wrote: »
    Chris,
    I can hand over all my sources if you like. The automation is all done with Bash scripts though. And it's an evolving beast, every day some changes are made. The useful parts in C are mostly the reconfigurable enhancements on the basic algorithms.
    That would be great! I do most of my development on a combination of MSVC and Windows Subsystem for Linux (Ubuntu).

    The only pipe-able version of TestU01 Big/Small/Crush that I have is for Windows, that I compiled with Cygwin... slow, but reliable. I compile for Linux for bigger jobs, though.
    I've generated about 30000 BigCrush results across about 50 PRNGs so I could perform meta-analysis to find weaknesses in my PRNGs and identify P-Val corrections for 20-30 of the BigCrush statistics.

    My work with PRNGs has been a mostly thank-less endeavor... but it does help fine-tune my logic skills for my day job (where I routinely connect with professionals all over the globe in diagnosing issues with analytical equipment... which requires proficiency in computer science, chemistry, physics, electronics, robotics, optics and mechanics).
  • xoroshironotxoroshironot Posts: 309
    edited 2019-04-09 22:46
    evanh wrote: »
    If you shuffled all output values from one full period and fed them into PractRand, it would likely fail at 2GB, but still probably 1GB.
    I didn't have a clue. So that's the nature of equidistribution then. Which I know we want to keep.
    I find 2 1-Dimensional equidistribution (e.g. xoroshiro32++) adequate for my work, however higher might be required for some uses.
    The theory goes that once you reach the square root of the period on a good PRNG (not sure how many dimensions), then an optimized analysis would reveal a statistically significant issue with an some of the outputs that are currently in deficit and excess suddenly changing toward excess and deficit at the same time (where normally only about half of those in either excess and deficit would head the other way).

    Some PRNGs (e.g. xoroshiro raw full-state output) will fail birthday spacings tests. Xoroshiro32+ will certainly fail tests looking for 3 consecutive same outputs.

    I am unaware of any statistical packages that attempt to make some of those judgement over longer periods and/or larger states, as the memory requirements are large.
    Melissa wrote one for birthday spacings that could identify and fail a single-dimensional 64-bit PRNG that uses only 1 state variable.
    PractRand is aware enough of various common issues to throw up a flag eventually, but not as soon as is theoretically possible in some cases.
    I found that Big Crush is only marginally aware of some issues, until you perform a meta-analysis of enough runs (sometimes hundreds) on a given PRNG.
  • Evan, just checking that I have the right file for the xoroshiro32++ distributions. Is it the following one?
    http://forums.parallax.com/discussion/comment/1447783/#Comment_1447783
  • evanhevanh Posts: 15,126
    Tony,
    Yep, that does seem to be correct, an almost complete set of single iterated freq distribution data.

    I can see I did a small run of double iterated the next day, but nothing since. I can't remember what I found with it.
  • TonyB_TonyB_ Posts: 2,108
    edited 2019-04-08 20:17
    Thanks, Evan. I've found the right QuickBASIC ranking programs amongst the mass of xoroshiro-related QB stuff, which means I can compare the xoroshiro32++ and xoroshiron32++ distributions and post the results.
  • evanhevanh Posts: 15,126
    edited 2019-04-08 15:16
    I'm looking at my own collection right now and it's so many old scripts I'm not sure what still works even. Scripts call scripts that compiles code which calls more code ... Parameter passing changes. Naming schemes change. Directory structures change. Source data changes.
  • TonyB_TonyB_ Posts: 2,108
    edited 2019-04-29 17:28
    Top 20 rankings:

    xoroshiro32++[a,b,c,d]
    #a, b, c, d,   prank,   zrank,  nzrank,    rank,    pchi,    zchi,   nzchi  
    13, 5,10, 9,       6,       5,       1,       1,      24,     327,     266
    13, 5, 8,10,       8,       7,       6,       2,      50,     337,     567
    14, 2, 9, 9,      10,       1,      17,       3,      68,     192,    1119
     7, 1, 8, 6,      12,       9,       8,       4,     109,     532,     598
     7, 2,14,13,      37,       2,       4,       5,     503,     203,     510
     7, 2,14,10,      27,       6,      16,       6,     315,     331,    1078
    14, 2, 7,10,      30,      19,       5,       7,     425,     967,     517
    14, 2, 9,10,      31,       8,      20,       8,     425,     481,    1145
     8, 1, 7, 5,      43,       3,      14,       9,     672,     264,     896
    11, 1, 2,13,      24,      16,      25,      10,     274,     710,    1317
     3, 3,10, 2,      39,      13,      21,      11,     592,     617,    1220
     8, 7,15,13,      18,      24,      41,      12,     212,    1124,    2054
    15, 6, 2, 9,      52,      34,       3,      13,     984,    1323,     488
     6, 2,11, 3,      76,       4,      12,      14,    1963,     324,     816
    14,12,13, 6,      15,      33,      62,      15,     162,    1292,    2445
    13,13,14,13,       3,      10,     103,      16,       8,     575,    3530
    14, 2, 7, 6,      71,      14,      33,      17,    1606,     624,    1662
     7, 2,14, 3,      47,      37,      51,      18,     760,    1581,    2267
     7, 2, 2, 5,      94,      42,       2,      19,    2768,    1800,     459
    14, 2, 7,15,      14,      55,      70,      20,     131,    2224,    2752
    

    xoroshiron32++[a,b,c,d]
    #a, b, c, d,   prank,   zrank,  nzrank,    rank,    pchi,    zchi,   nzchi  
    13, 5, 8,10,       6,       4,       2,       1,      19,     313,     437
    13, 5,10, 9,       8,       6,       1,       2,      27,     337,     254
     7, 2,14,13,      25,       2,       4,       3,     262,     249,     495
     7, 1, 8, 6,      15,      10,       7,       4,      91,     533,     614
    14, 2, 9, 9,      14,       1,      18,       5,      88,     198,    1124
     7, 2,14,10,      26,       7,      15,       6,     267,     364,    1054
    14, 2, 7,10,      32,      19,       5,       7,     377,    1013,     539
     8, 1, 7, 5,      44,       3,      14,       8,     653,     262,     892
    11, 1, 2,13,      17,      17,      29,       9,     136,     818,    1343
     8, 7,15,13,       7,      24,      34,      10,      26,    1123,    1579
    14, 2, 9,10,      39,       9,      22,      11,     520,     486,    1219
     3, 3,10, 2,      41,      14,      21,      12,     596,     616,    1219
    15, 6, 2, 9,      47,      34,       6,      13,     666,    1340,     563
     4, 1, 9, 5,      31,      45,      23,      14,     339,    1900,    1222
     6, 2,11, 3,      85,       5,      11,      15,    1965,     324,     815
    14, 2, 7,14,      13,      35,      54,      16,      87,    1415,    2212
    14,12,13, 6,      19,      30,      66,      17,     170,    1278,    2418
    13,13,14,13,       4,       8,     104,      18,      15,     457,    3402
    14, 2, 7, 6,      79,      15,      36,      19,    1650,     628,    1670
     7, 2,14, 3,      51,      38,      56,      20,     753,    1582,    2265
    

    prank/zrank/nzrank = pfreq/zfreq/nzfreq ranking
    rank = pfreq+zfreq+nzfreq ranking
    pchi/zchi/nzchi = Chi-Square total for pair/zero run/non-zero run frequency distributions
  • Here's the top 20 for xoroshiro32++ with not and right shifted b.
    #a, b, c, d,   prank,   zrank,  nzrank,    rank,   pfreq,   zfreq,  nzfreq  
     6, 5, 3, 2,       3,       5,       8,       1,       9,     310,     813
     2, 3, 3, 4,      13,       1,       2,       2,      60,     186,     453
     3,11, 2,10,       5,      11,       3,       3,      13,     412,     555
     2, 2, 7, 2,       6,       4,      15,       4,      17,     272,     992
    13, 3, 6, 4,       1,      26,      14,       5,       7,     774,     982
     2, 3, 3, 6,      45,       2,       1,       6,     461,     217,     278
     3,12, 2,10,      25,       9,      16,       7,     174,     403,    1028
     3,13, 2, 9,      14,      15,      26,       8,      63,     530,    1290
     4, 4, 1,10,      28,       3,      34,       9,     239,     260,    1529
     2, 2, 7, 3,      43,      16,       6,      10,     389,     534,     689
    14, 9, 7, 5,      44,      17,      19,      11,     424,     545,    1104
     4,10, 3, 4,      42,       6,      44,      12,     388,     318,    1736
     7, 1,12,13,      74,      14,       5,      13,    1110,     499,     679
    13,11, 2, 9,      57,       7,      33,      14,     634,     390,    1497
     4,10, 3, 9,      17,      54,      28,      15,     137,    1607,    1319
     5, 2,10, 6,      22,      48,      32,      16,     148,    1535,    1496
    13, 2,10,11,      64,      21,      17,      17,     802,     679,    1050
     6, 2, 9, 6,      19,      29,      61,      18,     141,     928,    1989
     6, 2, 9, 2,      56,      31,      25,      19,     632,     995,    1262
     8, 1, 9,12,      10,      46,      65,      20,      21,    1438,    2155
    
  • xoroshironotxoroshironot Posts: 309
    edited 2019-04-09 22:48
    I had mentioned upper limits on what could be expected from PractRand for a 2 1-dimensionally equidistributed PRNG like xoroshiro32++, so I did a few tests to re-confirm.

    Here is an example scrambler modification for use with the venerable 13,5,10,9, which I think pushes the upper limits of what is possible:
    rngword_t  result = s0 + s1 + (s1 << 2); // s0 + s1 * 5 
    result = rotl( result, CONSTANT_D ) + s0;
    
    Although I have no idea how that looks with regard to 'pair/zero run/non-zero run frequency', it does nearly exactly what I said in terms of PractRand:
    Almost passes at 1GB, such that 2GB seems that it will happen in a dozen or so tries. That is on both forward and reverse bits, with no notable differences between the two.

    That is the best measuring stick I have come up with.

    Edit: * 3 also works in the first line of the above code (i.e. 'result = s0 + s1 + s1 +s1' ), but slightly less balanced.
    However, it certainly can often make the 2GB mark before failing PractRand, but on forward bits only. Reverse bits fails at 1GB often (but not quite as gracefully as *5) or at 512MB sometimes.
  • evanhevanh Posts: 15,126
    edited 2019-04-09 02:21
    Any chance of something more parallelable like:
    	rngword_t  result = rotl( s0, CONSTANT_D ) + s0 + s1 + (s1 << 2);
    

    or:
    	rngword_t  result = rotl( s0 + (s1 << 2), CONSTANT_D ) + s0 + s1;
    
  • xoroshironotxoroshironot Posts: 309
    edited 2019-04-09 22:07
    Those two examples do not quite work (actually didn't check the last one you edited in the last one works, but not well), but it got me thinking.
    This is within a hair of my previous * 5 example (on both forward and reverse bits):
    rngword_t  result = rotl( s0 + s1, CONSTANT_D ) + s1 + (s1 << 2); // for some candidates '... + s0 + (s0 << 2)' will be better
    
    Quickly running out of simple variations that will work well.
  • evanhevanh Posts: 15,126
    Apologies for the silence. I decided to refactor the way the algorithms get compiled so that they now get linked instead of bundled in the one compile. It's decluttered the C sources quite a lot.

    Got a little sidetracked with the other work so still not finished ...

  • xoroshironotxoroshironot Posts: 309
    edited 2019-04-14 13:34
    For use with 128-bit state, I've been playing with the last * 5 scrambler that I posted on smaller state sizes and noticed that if it is paired with M<>0:
    1. 1-dimensional equidistribution is maintained in all cases, as expected... good.
    2. Single missing state, and thus the short output value (if left uncorrected by subtraction) is almost always non-zero, as expected... which is irrelevant with larger state sizes.
    3. Some values of M may produce, in addition to the normal output pairs, occasional triples, or even a rare quad depending on where M was inserted, which was unexpected... but likely ok.
    4. The 2-dimensional distribution accumulated across all values of M as a superset is not perfectly equidistributed, but so close that it looks viable. 1-d is perfect across the superset when y*5 is used, (but not x*5... probably ok).
    5. Speed with 128-bit state can be made equal to to xoroshiro128starstar, but with these notable differences: no accidental partial-invertibility (Melissa criticized, perhaps unfairly), only 1-D equidistribution, no perceptible escape-from-zero issues with vast majority of values of M, and since stream selection is via M, no jump function is required (but must test current state for single cycle loop when seeding and increment state, if necessary). This gives access to 2^64 total 2^128-1 period de-correlated streams... good.

    Beta code here: Xoroshiro128psp

    Even if you do not find anything useful out of all of this, I have benefited greatly from some of your and Tony's insights... Thanks!
  • xoroshironotxoroshironot Posts: 309
    edited 2019-04-13 20:54
    A few notes on the beta code I linked, as to how it would relate to use at 32-bit state with the choice of a single M (s[2] in the example):
    1. x * 5, was chosen for both its effect on superset near-perfect equidistribution and superior x64 compiled speed.
    2. y * 5 is likely the superior choice for a single value of M (even if M=0 or absent).
    3. Some otherwise unusable triplets may suddenly become viable with y * 5 or x * 5.
    4. A half-rotation in the scrambler may become viable. I looked specifically at 'rotl( x + y, 8 ) + y * 5;' (with or without M present).
    5. The position of M in the code is mostly relevant to speed/parallelization.
    6. None of the changes I have explored allow for simultaneously failing PractRand at 2GB with both forward and reverse bits (i.e. obtaining 2GB fail on reverse bits, usually fails at 512MB forward).
    7. The use of x/y * 5 in the latter-half of the the output scrambler makes the escape-from-zero issue much less apparent, thus has allowed me to focus more on using M as a steam selector.
  • evanhevanh Posts: 15,126
    edited 2019-04-13 22:22
    That's a little over my head but I think I'm learning.
    Comments:
    - I've never identified what constitutes a dimension in this world.
    - What's a stream?
    - "2^64 2^128-1" seemed a broken number until I looked at the linked page where it says "2^64 De-correlated, Jump-less Streams Each With Period 2^128-1 !!!"
    - The source code posted on that linked webpage is truncated. All I get is
    // Xoroshiro128psp Beta Test Code - Copyright Christopher Rutz - Free for all uses.
    // Based on xoroshiro128++ by S. Vigna / D. Blackman, and discussions of it with the Parallax development team.
    // Designed to address all common issues and criticisms of PRNGs, and to allow for most real usage scenarios without caveat.
    // Nearly-perfect 1-dimensional equidistribution (one output occurring 2^64-1 times and the rest 2^64 times).
    // All streams are nearly-perfectly de-correlated from each other, and form a super-set that is nearly-perfectly 2-dimensionally equidistributed.
    // Though not intended for cryptographic uses, the basic design is reasonably secure when seeded properly.
    // Any subset of output bits may be used for floating-point conversion.
    // Pipeline optimized for Intel CPUs, to meet the same performance speed of xoroshiro128**.
    
    #include <stdint.h>
    
    // Current state, seeded with any values by calling xoroshiro128psp_seed
    // Do not modify s[2] (stream selector) after seeding.
    uint64_t s[3] = { 0 , 0 , 1 };
    
    // 64-bit barrel-rotation, simplifies to single ROL op-code by most compilers
    inline uint64_t rotl(const uint64_t x, int k) {
        return (x << k) | (x >> (64 - k)); }
    
    // Returns a single 64-bit output value from the currently selected stream of 2^128-1 possible values
    inline uint64_t xoroshiro128psp() {
        uint64_t s0 = s[0];
        uint64_t s1 = s[1] ^ s[2];
        uint64_t result = rotl(s0 + s1, 33) + s0 * 5; // s0 * 5 = s0 + (s0 << 2)
        s1 ^= s0;
        s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16);
        s[1] = rotl(s1, 37);
        return result; }
    
    // Must use this function to seed both state variables and select a stream
    // It is recommended to use SplitMix to generate the seeds and stream selector for passing to this function
    void xoroshiro128psp_seed(uint64_t seed0, uint64_t seed1, uint64_t stream) {
        s[0] = seed0; s[1] = seed1; s[2] = stream;
        next();
        if (s[0]==seed0 && s[1]==seed1) { s[0] ^= 1ULL; }
    
    
  • xoroshironotxoroshironot Posts: 309
    edited 2019-04-15 01:13
    evanh wrote: »
    That's a little over my head but I think I'm learning.
    Comments:
    - I've never identified what constitutes a dimension in this world.
    - What's a stream?
    - "2^64 2^128-1" seemed a broken number until I looked at the linked page where it says "2^64 De-correlated, Jump-less Streams Each With Period 2^128-1 !!!"
    - The source code posted on that linked webpage is truncated. All I get is...
    1-Dimensional Equidistribution = Every output value appears an equal number of times (except some good PRNGs are short by 1 occurrance of a single output value).
    2-Dimensional Equidistribution = In addition to the above, each output value will occur in pairs an equal number of times, as well as every possible pair of different values.
    3-Dimensional Equidistribution = In addition to the above, all possible triplets are produced equally, which is good if you want the possibility of filling any/all points in a cube, for example.
    A Higher dimensional distribution may be obtained by using only a subset of bits of the above, thus a 64-bit output 1-D PRNG may be converted to floating point by dropping 12 bits and might possibly achieve up to 13-dimensional equidistribution... more than enough for working on the vast majority of problems.
    Some problems, like the (theoretical) ability to randomly generate all possible shuffles of a deck of 52 cards, (as I understand it) require a PRNG with a minimum of about 8*10^67 6-bit outputs. This is not quite within reach of xoroshiro128psp, even using all streams. Xoshiro256 can handle this easily. (I can't help but think there is a flaw in the logic of what I have read on card shuffling PRNGs, but never took the time to look).

    Streams are useful when parallelizing problem solving, as each stream provides a source that is not related to the others to maximize coverage and avoid invalid statistical inference.

    I fixed the odd way I wrote the numbers in the post.

    The code is complete now... it just needed an extra } at the end (which I wrap back to the end of the previous line out of poor habit), and I fixed the bad function call within the seed function.

    Thanks... now all I need is to run a minimum of 32TB of PractRand, 1PB of Hamming weight tests, a few hundred Big Crush tests for meta-analysis and a 10TB gjrand test.
  • evanhevanh Posts: 15,126
    1-Dimensional Equidistribution = Every output value appears an equal number of times (except some good PRNGs are short by 1 occurrance of a single output value).
    2-Dimensional Equidistribution = In addition to the above, each output value will occur in pairs an equal number of times, as well as every possible pair of different values.
    3-Dimensional Equidistribution = In addition to the above, all possible triplets are produced equally, which is good if you want the possibility of filling any/all points in a cube, for example.
    A Higher dimensional distribution may be obtained by using only a subset of bits of the above, thus a 64-bit output 1-D PRNG may be converted to floating point by dropping 12 bits and might possibly achieve up to 13-dimensional equidistribution... more than enough for working on the vast majority of problems.
    Some problems, like the (theoretical) ability to randomly generate all possible shuffles of a deck of 52 cards, (as I understand it) require a PRNG with a minimum of about 8*10^67 6-bit outputs. This is not quite within reach of xoroshiro128psp, even using all streams. Xoshiro256 can handle this easily. (I can't help but think there is a flaw in the logic of what I have read on card shuffling PRNGs, but never took the time to look).
    Thanks heaps. That's made it clear.

    Streams is way simpler than I expected. I hadn't considered you were referring to uses. Okay so M can be used as evenly spaced offsets to the state. But it won't be as simple as, say, invert msb of M to jump 50% through state space. It won't be that linear, right?
  • evanhevanh Posts: 15,126
    edited 2019-04-15 02:06
    Those two examples do not quite work (actually didn't check the last one you edited in the last one works, but not well), but it got me thinking.
    This is within a hair of my previous * 5 example (on both forward and reverse bits):
    rngword_t  result = rotl( s0 + s1, CONSTANT_D ) + s1 + (s1 << 2); // for some candidates '... + s0 + (s0 << 2)' will be better
    
    Quickly running out of simple variations that will work well.

    What about something like this, without a D?
    	rngword_t  result = s0 + (s0 << 1) + s1 + (s1 << 2);
    

    EDIT: Oh, that still has the bad bit0 doesn't it.
Sign In or Register to comment.