3

C# implementation of UnityEngine.Random with (almost) 1-to-1 parity

 4 months ago
source link: https://gist.github.com/macklinb/a00be6b616cbf20fa95e4227575fe50b
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C# implementation of UnityEngine.Random with (almost) 1-to-1 parity · GitHub

C# implementation of UnityEngine.Random with (almost) 1-to-1 parity

This is a partial C# implementation of UnityEngine.Random with (almost) 1-to-1 parity.

Unity uses Xorshift for psuedorandom number generation. In particular Xorshift128, which uses a state consisting of four unsigned 32-bit integer values. The state is initialized in UnityEngine.Random.InitState using a signed 32-bit integer seed, which is shuffled around with a technique similar to the way a Mersenne Twister is initialized.

This has been tested as far back as Unity 4.7.0f1, and as recent as Unity 2020.1.17f1.

Notes

  • Huge thanks to MoatShrimp for figuring out how Unity initializes the Xorshift state parameters in InitState, and floating point generation.
  • C# - As below. Values may differ in .NET 5.0, but thankfully Unity doesn't yet support that.
  • JavaScript - Check out MoatShrimp's JS implemention (and neat Undermine loot lookup tool) here:
  • Lua - I've translated this into Lua for use on MediaWiki wikis with the Scribunto extension installed. Note that this only works if Lua was compiled with LUA_NUMBER = double, which should be the case for most wikis. In my case the initial goal was to evaluate random loot lists in Pillars of Eternity, for use on the wiki.
  • If you translate this into other languages, or have any improvements/insights, feel free to comment below!
  • If you do translate this, be mindful of:
    • How your language handles numbers. Most programming languages that only define one type for numbers will use a double-precision floating point value to represent all numbers.
    • Integer overflow, and casting behaviours (particularly from uint to int)
    • Differences in the % operator (modulo vs remainder)

Unknowns

  • How Unity initializes UnityEngine.Random when a seed is not provided. Probably seeded based on time, perhaps hourly? Need to do further testiong.
  • Floating point RPG is slightly inaccurate. Unity's implementation is likely done differently, though their exact method is unknown.

Tests

The following tests were performed using the C# implementation in Unity, initialized with: UnityEngine.Random.InitState(1234) and XORShift128.InitSeed(1234), generated sequentially (the state isn't reset between runs).

UnityEngine.Random.State.s3 and XORShift128.w are the last state parameter in Xorshift, the actual number that was generated in Xorshift. This value is a uint and is used as a basis for all other Random functions.

Integer

Uses UnityEngine.Random.Range(min, max) and XORShift128.NextIntRange(min, max)

0 to int.MaxValue

s3 / w Unity XORShift
3463400838 1315917191 1315917191
3496203776 1348720129 1348720129
3452947669 1305464022 1305464022
1278673611 1278673611 1278673611
4169168310 2021684663 2021684663

0 to int.MinValue (-2,147,483,648)

s3 / w Unity XORShift
916287344 -916287344 -916287344
2240259090 -92775442 -92775442
1901252403 -1901252403 -1901252403
2323917162 -176433514 -176433514
1472147877 -1472147877 -1472147877

int.MinValue to int.MaxValue

s3 / w Unity XORShift
4020283508 1872799860 1872799860
141347300 -2006136348 -2006136348
2735243002 587759354 587759354
227819815 -1919663833 -1919663833
3885870057 1738386409 1738386409

int.MaxValue to int.MinValue

s3 / w Unity XORShift
2312142103 -164658456 -164658456
1775189369 372294278 372294278
3338523678 -1191040031 -1191040031
3426086347 -1278602700 -1278602700
3322349983 -1174866336 -1174866336

int.MinValue to int.MinValue (error is caught and a suitable value is returned before a value is even generated, hence the non-changing state value)

s3 / w Unity XORShift
3322349983 -2147483648 -2147483648
3322349983 -2147483648 -2147483648
3322349983 -2147483648 -2147483648
3322349983 -2147483648 -2147483648
3322349983 -2147483648 -2147483648

Floating point

Uses UnityEngine.Random.value and XORShift128.NextFloat()

s3 / w Unity XORShift
3593715923 0.4043221 0.404322
4266042159 0.551855 0.551855
2642301593 0.9868958 0.9868957
1674312536 0.593608 0.5936079
733387434 0.426595 0.426595

Uses UnityEngine.Random.Range(min, max) and XORShift128.NextFloatRange(min, max) 0.0 to 100.0

s3 / w Unity XORShift
3760331560 73.35463 73.35463
2410116911 69.16753 69.16753
3012185272 91.95337 91.95337
745993129 7.068896 7.068908
3699201620 2.080286 2.080297

0.0 to 100000.0

s3 / w Unity XORShift
1758944507 31747.49 31747.5
2312712917 30313.62 30313.62
313095164 67614.8 67614.8
609241099 37280.14 37280.14
4138924286 60177.63 60177.64

0.0 to float.MaxValue (3.402823E+38)

s3 / w Unity XORShift
3065852775 1.775827E+38 1.775827E+38
4023550175 1.209507E+38 1.209507E+38
1231330622 7.280383E+37 7.280387E+37
678488548 4.010639E+37 4.010643E+37
1997128070 3.143466E+38 3.143466E+38

0.0 to float.MinValue (-3.402823E+38)

s3 / w Unity XORShift
212231104 -2.382252E+38 -2.382252E+38
1632010759 -1.528401E+38 -1.528402E+38
3470161922 -1.104089E+38 -1.104089E+38
4159346095 -5.693158E+37 -5.693162E+37
3362607345 -4.967007E+37 -4.967012E+37

float.MinValue to float.MaxValue

s3 / w Unity XORShift
2641274177 -2.480102E+38 -2.480101E+38
3758475398 3.095331E+38 3.095331E+38
1138851524 -1.78091E+38 -1.780909E+38
3785966737 1.208649E+38 1.208649E+38
151368008 3.100158E+38 3.100158E+38

float.MaxValue to float.MinValue

s3 / w Unity XORShift
3347712278 -2.869245E+38 -2.869245E+38
2413123709 1.13493E+38 1.13493E+38
619907290 2.713464E+38 2.713463E+38
5796605 1.299941E+38 1.299941E+38
2534213977 -2.709683E+38 -2.709683E+38

float.MinValue to float.MinValue

s3 / w Unity XORShift
2990456181 -3.402823E+38 -3.402823E+38
238536240 -3.402823E+38 -3.402823E+38
3443233425 -3.402823E+38 -3.402823E+38
847449518 -3.402823E+38 -3.402823E+38
1964100510 -3.402823E+38 -3.402823E+38

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK