6

I've seen a lot of code where random numbers are generated like

// random integers in the interval [1, 10]
Math.floor(Math.random()*10 + 1)

Anyway, I feel like I'm missing something. Why don't people use the more succint way

Math.ceil(Math.random()*10);

?

I tried to test the randomness and it seems true so far.

In fact, the subsequent code

// will generate random integers from 1 to 4
var frequencies = [ 0, 0, 0, 0, 0 ]; // not using the first place
var randomNumber;
for ( var i = 0; i < 1*1000*1000; ++i ) {
   randomNumber = Math.ceil(Math.random()*4);
   frequencies[randomNumber]++;
}

for ( var i = 1; i <= 4; ++i ) {
   console.log(i +": "+ frequencies[i]);
}

prints out

1: 250103
2: 250161
3: 250163
4: 249573

What am I missing?

Quick OT: Is there a more succint way to declare and initialize frequencies? I mean like frequencies[5] = { 0 }; from C++...

Fabrizio Calderan
  • 120,726
  • 26
  • 164
  • 177
doplumi
  • 2,938
  • 4
  • 29
  • 45
  • 4
    `Math.ceil(Math.random()*10);` generates `[0,10]`, though the probability of `0` is very very small... – Passerby Apr 05 '13 at 09:46
  • Also, the probability of 10 is _slightly_ smaller than 1~9, because `Math.random()` **never** return 1. – Passerby Apr 05 '13 at 09:55
  • Concerning your OT question: Not really. JavaScript does not have array initialization. JavaScript arrays are (basically) nothing more than objects with numeric key names and a length attribute. The closest you can get is `new Array(size)`, but that does not initialize to 0, but to `undefined`. – jwueller Apr 05 '13 at 09:59
  • Also interesting to find that Math.ceil is ~90% slower than Math.floor : http://jsperf.com/convert-to-integer – Red15 Dec 05 '13 at 10:35

3 Answers3

9

as stated in MDN reference about Math.random()

Returns a floating-point, pseudo-random number in the range [0, 1) that is, from 0 (inclusive) up to but not including 1 (exclusive), which you can then scale to your desired range.

Since Math.random can return 0, then Math.ceil(Math.random()*10) could also return 0 and that value is out of your [1..10] range.


About your second question, see Most efficient way to create a zero filled JavaScript array?

Community
  • 1
  • 1
Fabrizio Calderan
  • 120,726
  • 26
  • 164
  • 177
  • 1
    I'm really curious now to see if getting 0 is actually possible, and if so, what the actual odds are! I tried it a few times with an edit of the question's script, *not* excluding zero, and with one billion random integers generated, which takes roughly 7 seconds to run, and `frequencies[0]` always returned zero. – Isaac Reefman Aug 30 '18 at 04:40
  • 1
    Wait, if [`Math.random()` returns 16 decimal places of accuracy](https://stackoverflow.com/a/3344463/9513577) I suppose it'd be one in ... ten quadrillion? Something like that? – Isaac Reefman Aug 30 '18 at 04:49
  • @IsaacReefman do you know Murphy's laws? :D. Anyway the probability is _nearly_ zero but not zero. – Fabrizio Calderan Feb 06 '20 at 10:42
  • 3
    @FabrizioCalderan Can confirm Murphy's law. I just had a node.js package that had worked reliably for months fail with a never-before-seen error while demoing an unrelated new feature to my team, because Math.random() chose *that* moment to return `0` for the first time. Lesson learned: if using Math.random() in a feature, have tests on it that run it against an array of varied values in place of the random value, and include `0` in that array – user56reinstatemonica8 Feb 25 '20 at 16:12
6

Math.floor() is preferred here because of the range of Math.random().

For instance, Math.random() * 10 gives a range of [0, 10). Using Math.floor() you will never get to the value of 10, whereas Math.ceil() may give 0.

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
1

random integers in the interval [1, 10]:

Math.floor(Math.random()*10 + 1)

random integers in the interval [0, 10]:

Math.ceil(Math.random()*10);

Just depends what you need.

jwueller
  • 30,582
  • 4
  • 66
  • 70
d'alar'cop
  • 2,357
  • 1
  • 14
  • 18
  • 1
    It would be a very bad way to get random numbers in the range of [0,10] when using ceil(), because zero effectively is starved. – Ja͢ck Apr 05 '13 at 10:02
  • Yes quite right... but it would be a shame to have some part of a system fall over one day because of a _very_ rare condition. – d'alar'cop Apr 05 '13 at 10:06
  • Not sure what you mean. But, if you are counting on 0 not being returned by the random() call then one day you may be unpleasantly surprised. That's all I'm saying. Also the whole point of this answer is to illustrate the difference between the 2 - he was implying they were the same... – d'alar'cop Apr 05 '13 at 10:13
  • You should delete this answer. `Math.ceil()` is _never_ the correct function to use when you want to generate random integers. Always use `Math.floor()` and then add the lower limit if it is nonzero. Taking your second example of `Math.ceil(Math.random()*10)` as an attempt to get numbers 0 through 10, the correct way to do this would be `Math.floor(Math.random()*11)`. – Michael Geary Nov 20 '17 at 20:53