Write a truly inclusive random method for javascript

前端 未结 9 1480
没有蜡笔的小新
没有蜡笔的小新 2020-11-30 11:25

Javascript\'s MATH object has a random method that returns from the set [0,1) 0 inclusive, 1 exclusive. Is there a way to return a truly random method that includes 1.

相关标签:
9条回答
  • 2020-11-30 11:54

    This should work properly.

    function random_inclusive () {
        while (true) {
            var value = Math.random() + (Math.random() < 0.5? 0: 1);
            if (value <= 1) {
                return value;
            }
        }
    }
    

    What we do here is generate additional single random bit to expand PRNG range to [0, 2). Then we simply discard values in (1, 2) and retry until our value hits in [0, 1].

    Notice that this method calls Math.random() 4 times on average.

    Alternatively, we can speed up things twice by the cost of 1 bit of precision:

    var value = Math.random() * 2;
    

    For those who want to test, here is the way. Just assume that Math.random() only has 1 bit of precision and generates either 0 or 0.5. So on the output we should have uniform distribution among values 0, 0.5, and 1.

    function random_inclusive_test (samples) {
        var hits = {};
        for (var i=0; i<samples; i++) {
            while (true) {
                var value =
                    (Math.random() < 0.5? 0: 0.5) +
                    (Math.random() < 0.5? 0: 1);
                if (value <= 1) {
                    break;
                }
            }
            if (!hits[value]) {
                hits[value] = 1;
            }
            else {
                hits[value]++;
            }
        }
        console.log(hits);
    }
    random_inclusive_test(300000);
    
    0 讨论(0)
  • 2020-11-30 11:55

    The solution I found was to use trigonometric equations.

    Because sine oscillates from Math.sin(0) = 0 and Math.sin(90) = 1. This repeats until 360 degrees which is equal to 0. However, 360 is still not highly precise so use radians which is 2 * Math.PI. You only need to take the absolute value to get rid of the negative values.

    So,

    double angle = 2 * Math.PI * Math.random() 
    double inclusive = Math.abs(Math.sin(angle)) // Math.cos(angle) also works.
    
    0 讨论(0)
  • 2020-11-30 11:59

    You want it to include 1?

    return 1 - Math.random();
    

    However, I think this is one of those questions which hints at other problems. Why do you need to include 1? There's probably a better way to do it.

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