True or better Random numbers with Javascript

前端 未结 8 672
花落未央
花落未央 2020-11-28 08:41

I have all kinds of resources that rely on javascript random numbers. However, I\'ve been seeing a lot of problems where random isn\'t so random because of the way I\'m gene

相关标签:
8条回答
  • 2020-11-28 09:14

    While looking for an alternative for Math.random I stumbled on this question.

    While those are valid answers, the solution that worked for me was simply using Math.random twice.
    And use a modulus on the decimals of the float.
    Basically to increase the randomness.

    Maybe it might be usefull for some who were guided by google to this question.

    Here's a snippet with the function, and one that runs it a million times.

    function rand(min, max){
        return (Math.floor(Math.pow(10,14)*Math.random()*Math.random())%(max-min+1))+min;
    }
    
    // testing rand
    function rollRands(min, max, rolls) {
        let roll = 0, n = 0;
        let counts = {};
        
        for(let i = min; i <= max; i++){
            counts[i]=0
        }
    
        while (roll < rolls){
            roll++;
            counts[rand(min,max)]++;
        }
        return counts;
    }
      
    console.log(rollRands(36, 42, 1000000));

    0 讨论(0)
  • 2020-11-28 09:16

    Tweaking numbers so they "look random"

    I agree with Phil H that humans are so good at finding patterns that they often think they see patterns even in "perfectly random" sequences of numbers (clustering illusion, apophenia, gambler's fallacy, etc).

    Plots of true random positions generally have lots of clumps and points that "coincidentally" fall very close together, which looks pretty suspicious.

    Artists often take completely randomly generated patterns and "nudge" them to make them appear "more random", even though that careful nudging actually makes the pattern less random (a), (b), (c), (d), etc.

    Alternatively, a low-discrepancy sequence sometimes "looks better" than a true random sequence and is much faster to generate.

    Fast random number generators

    There are many "random number generators" across a whole spectrum from "extremely fast" to "relatively slow" and from "easy for even a human to see patterns" to "unlikely that unassisted humans could ever see any patterns" to "cryptographically secure and, after seeded with adequate amounts of entropy, as far as we can tell, indistinguishable from random to any attacker using less than all the energy produced by humanity for a month."

    Non-cryptographic-strength random number generators that still give excellent output (unlikely that unassisted humans could ever see any patterns) include the Mersenne twister, multiply-with-carry, Lagged Fibonacci generator, Well equidistributed long-period linear, Xorshift, etc.

    Cryptographic random number techniques that work with some browsers

    I hear that Cryptocat and other JavaScript applications use the convenient window.crypto.getRandomValues() or window.msCrypto.getRandomValues() or SubtleCrypto.generateKey() functions that are designed to generate cryptographic random numbers. Unfortunately, that function is not available in IE 11 and below.

    Since web browsers use random numbers all the time (for every "https://" page they fetch), it's quite likely that these functions (where available) may run faster than most random number generators written in JavaScript -- even non-cryptographic algorithms.

    Cryptographic random number techniques compatible with ancient and modern browsers

    One way to generate true random numbers in JavaScript is to capture mouse events and add them into a pool of entropy, keeping track of some (hopefully conservative) estimate of the entropy added. Once the pool is "full" (estimates indicate that at least 128 bits of entropy have been added), use some cryptographically secure random number generator to generate random numbers from the pool -- typically by using a one-way hash so that a sequence of a few thousand output numbers are not enough to deduce the state of the entropy pool and hence predict the next output number.

    One implementation: http://lightsecond.com/passphrase.html

    Further reading

    • window.crypto
    • Compatibility of window.crypto.getRandomValues()
    • Secure random numbers in javascript?
    • https://security.stackexchange.com/questions/20029/generate-cryptographically-strong-pseudorandom-numbers-in-javascript
    • Is there any built in browser support for crypto random numbers in IE and Webkit? Firefox has window.crypto
    • Better random function in JavaScript
    0 讨论(0)
  • 2020-11-28 09:17

    Assuming you're not just seeing patterns where there aren't any, try a Mersenee Twister (Wikipedia article here). There are various implementations like this one on github.

    Similar SO question:

    Seedable JavaScript random number generator

    If you want something closer to truly random, then consider using the random.org API to get truly random numbers, although I would suggest only using that to seed, not for every number, as you need to abide by their usage limits.

    0 讨论(0)
  • 2020-11-28 09:18

    Rando.js is cryptographically secure. It's basically window.crypto.getRandomValues() that uses window.msCrypto.getRandomValues() as a failsafe and Math.random() as a last resort failsafe, but it's easier to implement and use. Here's a basic cryptographically secure random [0, 1) number:

    console.log(rando());
    <script src="https://randojs.com/2.0.0.js"></script>

    Nice and easy. If that's all you wanted, you're good to go. If you want it to do more for you, it's also capable of all this:

    console.log(rando(5));                      //an integer between 0 and 5 (could be 0 or 5));  
    console.log(rando(5, 10));                  //a random integer between 5 and 10 (could be 5 or 10));  
    console.log(rando(5, "float"));             //a floating-point number between 0 and 5 (could be exactly 0, but never exactly 5));  
    console.log(rando(5, 10, "float"));         //a floating-point number between 5 and 10 (could be exactly 5, but never exactly 10));  
    console.log(rando(true, false));            //either true or false  
    console.log(rando(["a", "b"]));             //{index:..., value:...} object representing a value of the provided array OR false if array is empty  
    console.log(rando({a: 1, b: 2}));           //{key:..., value:...} object representing a property of the provided object OR false if object has no properties  
    console.log(rando("Gee willikers!"));       //a character from the provided string OR false if the string is empty. Reoccurring characters will naturally form a more likely return value  
    console.log(rando(null));                   //ANY invalid arguments return false  
    
    //Prevent repetitions by grabbing a sequence and looping through it
    console.log(randoSequence(5));              //an array of integers from 0 through 5 in random order  
    console.log(randoSequence(5, 10));          //an array of integers from 5 through 10 in random order  
    console.log(randoSequence(["a", "b"]));     //an array of {index:..., value:...} objects representing the values of the provided array in random order  
    console.log(randoSequence({a: 1, b: 2}));   //an array of {key:..., value:...} objects representing the properties of the provided object in random order  
    console.log(randoSequence("Good gravy!"));  //an array of the characters of the provided string in random order  
    console.log(randoSequence(null));           //ANY invalid arguments return false
    <script src="https://randojs.com/2.0.0.js"></script>

    It supports working with jQuery elements too, but I left that out of this demo so I wouldn't have to source in jQuery. If you need that, just check it out on the GitHub or website.

    0 讨论(0)
  • 2020-11-28 09:18

    There seems to be slight confusion here between two things that are very different:

    • random numbers;
    • pseudorandom numbers.

    Apologies to those who know this already, but the two are worlds apart. Pseudorandom numbers appear random and may even pass sophisticated tests of randomness, but they are deterministic. Because of this, they are useless for cryptography, and may have other flaws where true randomness is required.

    True randomness is non-deterministic, and thus unpredictable. A key concept here is one of entropy, or the amount of non-redundant information contained. There is a limited number of ways of obtaining truly random data. 'Good' sources are:

    1. Radioactive decay — often difficult to do;
    2. Background radio noise — contrary to popular believe, this is mostly not related to the background microwave radiation from the big bang, but more parochial;
    3. The noise from electrons moving across a reverse-biased Zener diode: actually quite useful and easy to implement in practice, with simple circuitry.

    Other 'sources of randomness' like mouse movements and internal variations in computer disk timing, etc. are often harnessed, but may be less-than-perfect. Generally, I've found that it's easier to access the entropy pool on a Linux system than under Windows, but this may just be personal bias.

    If you just want random-appearing numbers, then yes, using the Mersenne twister is a viable option. It jumps around like crazy. If you're generating random numbers to use as e.g. version 4 UUIDs, then you need to be more careful. You can't simply 'add entropy' if it's not there, even by applying deterministic cryptographic functions.

    If you intend to use your randomness for cryptography, you should also be intensely aware of the many ways your source of randomness can become compromised. For example, if you're using an Internet-based 'source of randomness', who can tap into this?

    0 讨论(0)
  • 2020-11-28 09:19

    you can generate a pool of random numbers just by requesting some data asynchronously because performance.now() gives you time precision up to microseconds. Then use the response time as a salt in a randomising algorithm,

    var randomNumbers = [];
    for(var i = 0; i < 10; i++) {
      setTimeout(function () {
        var timeStart = performance.now();
        xhttp = new XMLHttpRequest();
        xhttp.open('GET', 'https://cdn.polyfill.io/v2/polyfill.min.js?rand=' + Math.random(), true);
        xhttp.onload = function () {
          var timeEnd = performance.now() - timeStart;
          var rNumber = parseInt(timeEnd.toString().replace('.', ''));
          randomNumbers.push(rNumber)
        };
        xhttp.send();
      }, i * 10);
    }
    

    There are many factors that will affect this time:

    • browser speed
    • route one way
    • server response time
    • route back

    It's not good to generate millions of numbers this way but a few. Maybe concatenate a few results to get a good, long random number.

    0 讨论(0)
提交回复
热议问题