2

Hi I found this piece of JS code which generates zero or one: I don't understand how the pipe (ORing) is involved here?

  var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1​

I found another way

Math.floor(Math.random()*2)

which accomplishes the same goal. Which one is preferred?

kogibail
  • 125
  • 1
  • 2
  • 10
  • 1
    well, obscurity is usually less good, but that's just my opinion i guess. https://stackoverflow.com/questions/6194950/what-does-the-single-pipe-do-in-javascript – Andrew Feb 15 '18 at 20:40
  • 3
    Why the `+ 1) - 1)` I wonder? Seems like `(Math.random () * 2 | 0)` would be enough on its own. – Yuck Feb 15 '18 at 20:40
  • For the sake of readability, the second option is better, plus it's less operations so micro-optimized. See https://stackoverflow.com/questions/6194950/what-does-the-single-pipe-do-in-javascript – Sterling Archer Feb 15 '18 at 20:41
  • @Dummy - Not useless at all. The bitwise OR first converts the operands to integers. – Ted Hopp Feb 15 '18 at 20:42
  • @Dummy Not entirely _useless_. The (desired) side-effect is truncation of the non-zero operand to an integer. Pretty unreadable code, however. – Yuck Feb 15 '18 at 20:43
  • Simpler and clearer would be `(Math.random() < 0.5) ? 0 : 1` – Lee Daniel Crocker Feb 15 '18 at 20:43
  • @TedHopp isn't that what the `+` operator is for? – Tibrogargan Feb 15 '18 at 20:43
  • @LeeDanielCrocker a ternary never makes things simpler :P – Sterling Archer Feb 15 '18 at 20:43
  • @Tibrogargan - No. That will leave the result as a floating point number if it started that way. – Ted Hopp Feb 15 '18 at 20:43
  • @LeeDanielCrocker - Ternary operators tend to mess with predictive instruction pipelines, negatively impacting performance. – Ted Hopp Feb 15 '18 at 20:45
  • @TedHopp Then I'm going with `~~(Math.random() * 2)` – Tibrogargan Feb 15 '18 at 20:46
  • @Tibrogargan - Yeah, that's another well-known trick for turning a number into an integer. But it escapes me why anyone would prefer using two bitwise operations when the job can be done using only one, especially if performance is important. – Ted Hopp Feb 15 '18 at 20:50
  • 1
    @LeeDanielCrocker Or just `+(Math.random() < 0.5)`. – Bergi Feb 15 '18 at 20:50
  • I wouldn't make too many assumptions regarding branch prediction vs bitwise operations in JS, especially with modern optimizing compilers. And I especially wouldn't give it two thoughts unless there were many, many of these numbers being generated. –  Feb 15 '18 at 20:55
  • @Tibrogargan - Except the `+ 1) - 1;` part isn't needed at all. – Ted Hopp Feb 15 '18 at 20:55
  • @TedHopp yup. too small focus. Wondering if the guy was trying for "random integer between 1 and 2" – Tibrogargan Feb 15 '18 at 20:56
  • how is fraction represnted in binary? random() gets fraction and result is ORed? – kogibail Feb 15 '18 at 21:16

2 Answers2

7

"I don't understand how the pipe (ORing) is involved here?"

The pipe is the bitwise OR operator, and is just used here as a short way to get rid of the fractional part of the random number.

So the random number generates something from 0 to 1.9999999999, and dropping the decimal gives you 0 or 1.

"Which one is preferred?"

I'd say clarity if preferred in your general code, so Math.floor().

You could also do this:

var randomNum = Math.random() < 0.5 ? 0 : 1;
  • u could also move the more obscure but better performance code into a nicely named function, thereby keeping the code readable. – Andrew Feb 15 '18 at 20:45
  • True. Some would say that the obscure version should never exist, but I think it's just fine in library code, though I don't know if there's much real benefit to it overall even there. –  Feb 15 '18 at 20:47
1

You could use Math.round(Math.random()), which makes rounding and returns zero and one only. It is equally distributed.

var i = 1e7,
    count = [0, 0];

while (i--) {
    count[Math.round(Math.random())]++;
}

console.log(count);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392