Guest User

JS Xoroshiro128+ , splitmix64 RNG

a guest
Aug 18th, 2016
620
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //random with seed & range
  2. (function(window) {
  3.     //scope it so closure contains only relevant internal state
  4.  
  5. window.performance = window.performance || {};
  6. performance.now = (function() { //use high res time
  7.   return performance.now       ||
  8.          performance.mozNow    ||
  9.          performance.msNow     ||
  10.          performance.oNow      ||
  11.          performance.webkitNow ||
  12.          function() { return new Date().getTime(); };//shim for old browsers
  13. })();
  14.  
  15. var c=1;
  16.     window.RND = function(s, min, max) {
  17.         //uses next gen v8 js engine random (splitmix64 seed & Xoroshiro128+ rng)
  18.         //which is better than (murmurhash3 & xorshift128+) currently used in browsers
  19.         //this rng also supports custom seed , and min max range limit(both inclusive)
  20.         //(this class depends on using Long.js 3rd party lib)
  21.        
  22.         //should be positive
  23.         max = max || 1;
  24.         min = min || 0;
  25.  
  26.         var state0_;
  27.         var state1_;
  28.        
  29.         var seedInit;//readonly, used for changing min-max without the seed
  30.  
  31.         max += 1; //make max inclusive
  32.        
  33.         //if (max > 32767) //after that, ditribution might not be uniform(probably only in c lang rand())
  34.         //    max = 32767;
  35.  
  36.         setSeed(s);
  37.         Xoroshiro128plus(state0_, state1_);//do 1st round before call, so result won't be only of seeding
  38.  
  39.         function setSeed(seed) {
  40.             seedInit = initSeed(seed);
  41.             splitmix64(seedInit);
  42.         }
  43.  
  44.         function initSeed(seed) {
  45.             //seed shouldn't be 0
  46.             if (seed == null || seed <= 0)
  47.                 seed = genSeedFunc(Math.random());          
  48.  
  49.             if(seed<30000)
  50.                seed=(seed^(seed*seed))+seed;//more entropy, bigger number
  51.            
  52.             return seed;
  53.         }
  54.         function genSeedFunc(r){
  55.             if (r == null || r <= 0)
  56.                 r=Math.random();
  57.                
  58.            return Math.floor((r*(c++))*(~performance.now()^Date.now()));
  59.         }
  60.        
  61.         function splitmix64(seed) { //64bit      
  62.             //test input/output  of splitmix64  & Xoroshiro128plus
  63.             //https://ideone.com/PuauK5
  64.  
  65.             var x = new Long(seed, 0, false);
  66.             //Long.fromString is a little slower (because of intParse,multiply,loop length)
  67.            
  68.             //round 1
  69.             x = x.add(Long.fromString("0x9E3779B97F4A7C15", false, 16));
  70.  
  71.             z = x;
  72.             z = z.xor(z.shiftRightUnsigned(30));
  73.             z = z.multiply(Long.fromString("0xBF58476D1CE4E5B9", false, 16));
  74.             z = z.xor(z.shiftRightUnsigned(27));
  75.             z = z.multiply(Long.fromString("0x94D049BB133111EB", false, 16));
  76.             z = z.xor(z.shiftRightUnsigned(31));
  77.  
  78.             state0_ = z;
  79.             //round 2
  80.             var z = x.add(Long.fromString("0x9E3779B97F4A7C15", false, 16));
  81.  
  82.             z = z.xor(z.shiftRightUnsigned(30));
  83.             z = z.multiply(Long.fromString("0xBF58476D1CE4E5B9", false, 16));
  84.             z = z.xor(z.shiftRightUnsigned(27));
  85.             z = z.multiply(Long.fromString("0x94D049BB133111EB", false, 16));
  86.             z = z.xor(z.shiftRightUnsigned(31));
  87.  
  88.             state1_ = z;
  89.            
  90.             //this function might not be accurate after round 3 (but usually only the first 2 are needed)
  91.         }
  92.  
  93.         function rotL(x, k) {
  94.             var v1 = x.shiftLeft(k);
  95.             var v2 = x.shiftRightUnsigned(64 - k);
  96.             return v1.or(v2);
  97.         }
  98.  
  99.         function Xoroshiro128plus(s0, s1) { //128bit
  100.             var result = s0.add(s1);
  101.  
  102.             s1 = s1.xor(s0);
  103.             state0_ = rotL(s0, 55).xor(s1).xor(s1.shiftLeft(14));
  104.             state1_ = rotL(s1, 36);
  105.  
  106.             return result;
  107.         }
  108.        
  109.         function genRandInternal(){
  110.             var sum = Xoroshiro128plus(state0_, state1_);
  111.             //to double
  112.            
  113.             var random = toDouble(sum.toString());
  114.             return random;
  115.         }
  116.        
  117.        
  118.         function toDouble(str)
  119.         {
  120.             if (str.startsWith("-"))//make positive
  121.                 str = str.substr(1);
  122.                
  123.             var result = "0." + str;
  124.             var random = parseFloat(result);
  125.            
  126.             return random;
  127.         }
  128.  
  129.         return function() {
  130.             var random = genRandInternal();
  131.            
  132.             if ((max - 1 - min) <= 2) {
  133.                 //try 2 times to not pass min/max for better randomness
  134.                 if ((random > 1) || (random < 0)) {
  135.                     random = genRandInternal();
  136.                     if ((random > 1) || (random < 0)) {
  137.                         random = genRandInternal();
  138.                     }
  139.                 }
  140.             }
  141.        
  142.             //set to range if overflow
  143.             if (random > 1) random = 1;
  144.             else if (random < 0) random = 0;
  145.        
  146.             //range check , random = 0-1 double , used as precentage of the range
  147.             var r = (min + (random * (max - min))) % (max + 1);          
  148.             if (r > max-1) r = max-1;
  149.             else if (r < min) r = min;
  150.            
  151.             return {
  152.                 value: r,
  153.                 seed_:seedInit,
  154.                 toBool: function() {
  155.                     //random bool
  156.                     return (random > 0.5);
  157.                 },
  158.                 toInt: function() {
  159.                         return Math.floor(r);
  160.                     },
  161.                     getSeed: function(){
  162.                         //for new RND instance with different min,max
  163.                         return  genSeedFunc(random);
  164.                     }
  165.                     //,function NextBytes(arrSize){}
  166.             }
  167.         };
  168.         //also can can do after -128 if you want a number between -128 , 128 (using min 0 and max 256)
  169.     }
  170. })(window);
Advertisement
Add Comment
Please, Sign In to add comment