11

I am using

var min = -13;
var max = 13;
var random = Math.floor(Math.random() * (max - min + 1)) + min;

but it returns ALL numbers(random) between -13 and 13. how can i get it to generate a random number between -13 to -4 exluding -3 , -2, -1, 0 , 1 ,2 ,3 and including 4 to 13.

Yusaf Khaliq
  • 3,333
  • 11
  • 42
  • 82
  • I don't think that this is possible. I would make an array with the values you want and randomly access the array – mas-designs Feb 16 '12 at 12:51
  • 1
    @EvilP, that would convert a constant time and space operation to a linear time and space one. That's like adding 100 to a number by adding 1 one hundred times. It works, but is, to say the least, unadvisable. – davin Feb 16 '12 at 12:57
  • @davin how is array access linear time operation – Esailija Feb 16 '12 at 12:59
  • @Esailija, I didn't say it is, although creating the array is linear time. In fact, technically it's exponential space and time, because the input is logarithmic in its value. – davin Feb 16 '12 at 13:02
  • @davin the operation itself doesn't involve creating arrays, the array is precreated, – Esailija Feb 16 '12 at 13:08
  • @Esailija, and what if there are different ranges? You might need different arrays for each time, how do you precreate every possible array? – davin Feb 16 '12 at 13:10
  • @davin needing to have different ranges each time is a situation where it would be linear time operation yes. – Esailija Feb 16 '12 at 13:12
  • @Yusaf - you should take a few minutes to check out the comps James put together, and the various revisions to them. If nothing else it is interesting to see how the "winning" solution changes based on browser versions. [http://jsperf.com/random-number-generation](http://jsperf.com/random-number-generation) – Rozwel Feb 16 '12 at 14:12

7 Answers7

16

Get a random number between 1-10 and add 3, to get one between 4-13:

random = Math.ceil(Math.random() * 10) + 3;

Generate a random between 0-1. If it's 0, make the number negative:

random = (Math.floor(Math.random() * 2) == 0) ? 0 - random : random;

JSFiddle showing working copy:

http://jsfiddle.net/adamh/cyGwf/

Adam Hopkinson
  • 28,281
  • 7
  • 65
  • 99
  • 1
    the sign can be easily generated simply by `random = (Math.random() < 0.5)? -random : random;` no need to call `math.floor` – Fabrizio Calderan Feb 16 '12 at 12:54
  • The risk is extremely small, but knowing that Math.random() delivers values [from 0 (including!) to 1 (excluding!)](http://stackoverflow.com/q/11730263), the first line COULD deliver a value of 3. Hence a slightly cleaner practice to go with Math.floor and work from there: `random = Math.floor(Math.random() * 10) + 4;` – Frank N Apr 03 '13 at 07:34
1

As far as I know, it's not possible to generate a random number and take into account an exclusion set. You need to create a recursive function to do the filtering for you. See below:

function GenerateRandomNumber() {
    var min = -13, max = 13;
    var random = Math.floor(Math.random() * (max - min + 1)) + min;   

    // If random number is undesirable, generate a new number, else return
    return (random < 4 && random > -4) ? GenerateRandomNumber() : random;
}

var myRandomNumber = GenerateRandomNumber();
​

Here's a working fiddle.

Or, courtesy @Rozwel, a non-recursive version using a while loop:

function GenerateRandomNumber() {
    var min = -13, max = 13;
    var random = 0;

    while (random < 4 && random > -4) {
        random = Math.floor(Math.random() * (max - min + 1)) + min;
    }

    return random;
}

Here's a jsperf that compares the accepted answer with these two options.

James Hill
  • 60,353
  • 20
  • 145
  • 161
  • you could theoretically enter in an infinite loop – Fabrizio Calderan Feb 16 '12 at 12:56
  • @FabrizioCalderan, are you serious? -1 for a theoretical (though mathematically impossible) possibility? – James Hill Feb 16 '12 at 12:58
  • 1
    @JamesHill, The code will enter a loop with zero probability, and has a linear expected running time, so theoretically this code is not too bad. Did you downvote your own post? – davin Feb 16 '12 at 13:00
  • @JamesHill -1 because there's nothing that prevent the function to generate -2, 1, 2, -3... many times before outputting a valid value. At university I saw some people rejected for this kind of logic. In practical terms you won't have an infinite loop but this still is inefficient for above reason – Fabrizio Calderan Feb 16 '12 at 13:07
  • @FabrizioCalderan, I suggest that you take a look at this jsperf - http://jsperf.com/random-number-generation. Can you explain why my solution is faster than the highest voted solution every time? – James Hill Feb 16 '12 at 13:12
  • @james Not down voting, but I have to say this seems like a poor case for recursion. You could get the same result with a while loop without the overhead of nested function calls. – Rozwel Feb 16 '12 at 13:14
  • @Rozwel, again, please take a look at the jsperf - I'm not saying this is the **best** possible solution, but I think it's getting a pretty bad rap... – James Hill Feb 16 '12 at 13:15
  • @jameshill: I think you don't get the point. http://i43.tinypic.com/1y1nbs.png. In theory you cannot be sure to have a termination and in practical terms your function can call itself many times before terminate. – Fabrizio Calderan Feb 16 '12 at 13:21
  • I don't think this is infinite even in theory as `Math.random()` is not a real random number generator – Esailija Feb 16 '12 at 13:26
  • @FabrizioCalderan, you can't just take one test case and post a picture. Look at the data as a whole, admin that you're incorrect, and remove your -1. http://i41.tinypic.com/k9tbhu.jpg – James Hill Feb 16 '12 at 13:29
  • @james all I was pointing out was you could do the same thing without the recursion overhead. I added a third case to your test using a while loop, and at least in my environment the multiple randoms is winning with the while version slightly edging out the recursive solution for second place. [jsperf.com/random-number-generation/2](http://jsperf.com/random-number-generation/2) – Rozwel Feb 16 '12 at 13:29
  • @Rozwel, Ahh. Great point - great suggestion. I'll add that to my answer. – James Hill Feb 16 '12 at 13:31
  • 1
    Not sure how it will affect the results, but these test cases are pretty useless; sometimes you have the code in a function, sometimes not, sometimes you use hardcoded magic numbers, sometimes you use variables. All these discrepancies change lookup times etc. As such, as is the data isn't very useful. – davin Feb 16 '12 at 13:43
  • @davin, they aren't magic numbers, they are the numbers requested in the OP. – James Hill Feb 16 '12 at 13:46
  • Just for grins I threw my subtraction solution into the ring as well. I find the differences across browsers quite interesting. I would not have expected the results to vary quite so dramatically... – Rozwel Feb 16 '12 at 13:46
  • Well, this has blow up quite a bit. I was simply trying to prove that this answer was not worth a `-1`... – James Hill Feb 16 '12 at 13:48
  • They're magic if in one place you write `10` and in another you write `max-min+1` which involves two lookups, extra parsing, and two ALU operations assuming there aren't optimisations. – davin Feb 16 '12 at 13:48
  • @Davin Your point made me curious so I expanded the test to include revisions that brought things closer into line. At least for my browser moving the multiple randoms into a function made a dramatic impact while replacing the “magic numbers” with variables was a minor change. – Rozwel Feb 16 '12 at 14:06
  • http://jsperf.com/random-number-generation/4 Not surprisingly there's almost no difference. These are micro-optimisations. However from my tests it looks like the recursion is every so slightly slower, presumably because there's now more overhead in each branch because of the extra variable bindings. The other two are almost the same because a single function call vs. an extra iteration or two seem similar. – davin Feb 16 '12 at 14:10
  • @Rozwel, notice that my tests merely call the functions, they don't create them. I've tried to be consistent across all tests. I've also tried to be real-world - the functions need parameters. – davin Feb 16 '12 at 14:12
  • Please take it to one of the [chat rooms](http://chat.stackoverflow.com/). Comments aren't intended for extended discussions. – Bill the Lizard Feb 16 '12 at 14:17
  • Admittedly, my testing is flawed in that I'm only testing 4,13 as arguments, and should be testing the behaviour across a wider range of values to assess differences. For reasonable values the range in this case shouldn't make much of a difference. However the loop and recursive versions will be significantly slower for "unreasonable" values, like 500,501. – davin Feb 16 '12 at 14:17
1

Minor tweak to what you have should do it. Produce a random in the range of -6 to 13, and then if the value is less than 4, subtract 7. I have not tested it, but I suspect it would perform better than producing two randoms and multiplying.

var min = -6; 
var max = 13; 
var random = Math.floor(Math.random() * (max - min + 1)) + min; 
if(random < 4){random = random - 7;}
Rozwel
  • 1,990
  • 2
  • 20
  • 30
1
var pickOne = [4,5,6,7,8,9,10,11,12,13],
    value   = pickOne[Math.floor(Math.random() * pickOne.length)];

value   = (Math.random() < 0.5)? value : -value;
console.log(value)
Fabrizio Calderan
  • 120,726
  • 26
  • 164
  • 177
0
var n = Math.floor(Math.random() * 20) - 10;
n = n < 0 ? n - 3 : n + 4;
4esn0k
  • 9,789
  • 7
  • 33
  • 40
0
var sign = Math.round(Math.random()) == 0 ? -1 : 1;
var number = Math.round(Math.random() * 9) + 4;
return sign * number;
gabitzish
  • 9,535
  • 7
  • 44
  • 65
0

Math.round(Math.random()) returns 0 or 1,

so it can be written with no intermediate value:

alert( (Math.ceil(Math.random() * 10) + 3)*(Math.round(Math.random())?1:-1));
kennebec
  • 102,654
  • 32
  • 106
  • 127