Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Random Number Generator - How would you write it?

Edit: Throughout this thread, I misused the term 'set or set notation' when I should have said 'interval notation'. Also, I reversed the meaning of the symbols for interval notation: brackets [] are inclusive, parens () are exclusive. The leading comments for the function below have been fixed, but the rest of the thread will remain as is. If you're not making any mistakes, you're not trying hard enough - or so I tell myself.

I've visited this idea several times, and each time I keep wondering 'How can I make this more robust?'. So, I wonder if any of you have a favorite way of writing an RNG function - perhaps we can learn something from each other?

Here is my (current) version:

/**
     * rng();         // random floating-point number [0, 1)
     * rng(10);       // random whole number [0, 10)
     * rng(2, 5);     // random whole number [2, 5]
     * rng(5, 2);     // random whole number [2, 5]
     * rng('a', 'b'); // random floating-point number [0, 1)
     * rng(-3, -2);   // random floating-point number [-3, -2)
     * rng(2, 3);     // random floating-point number [2, 3)
     *
     * The single argument call is the most interesting to me, as it easily
     * allows for generating a random index value based on the length of
     * a string or array. For example:
     *
     * var myArray = [1, 2, 3];
     * var randomArrayValue = myArray[rng(myArray.length)];
     *
     * or ...
     *
     * var dinnerList = ['pizza', 'hamburgers', 'tacos'];
     * var dinnerForTonight = dinnerList[rng(dinnerList.length)];
     */
    function rng(max, min) {
      var minDefined = min ? true : false;
      var inclusiveMax = minDefined ? 1 : 0;
      var min = Number(min) || 0;
      var max = Number(max) || 1;
      if (min > max) { max = [min, min = max][0]; }
      if (max - min === 1) { return Math.random() + min; }
      else { return Math.floor(Math.random() * (max - min + inclusiveMax)) + min; }
    }

I'm open to any and all feedback. A nagging thought I have is perhaps I can use a better variable name instead of 'inclusiveMax' - perhaps making it a function called isInclusive() which returns a 0 or 1.

The idea being that if a user calls rng() with both min and max defined, like rng(1, 10), I suppose they would expect a random whole number value from 1 - 10, inclusive, which is 10 possibilities.

This requires adding 1 after finding the difference between min and max - hence the variable 'inclusiveMax' which holds a 0 or 1 depending if min is defined.

1 Answer

Looks like a nice function! Interestingly enough, the variable you're unsure of is technically not needed. Mind you, I don't have deep knowledge for JS itself, but if it's the same as any of the other languages I'm familiar with, all you need is the minDefined variable.

Boolean values are essentially integers, 1 being true and 0 being false. By explicitly stating that true = 1 and false = 0 with inclusiveMax, you're accomplishing the same thing but with an extra variable.

If you removed the inclusiveMax declaration, and replaced inclusiveMax with minDefined inside of the else statement , it should work the same.

Just a little tidbit I thought was interesting, it really comes down to which one you find is more readable.

Hi Justin,

Thanks for your feedback! You're absolute correct. JavaScript will coerce the value of minDefined into a 0 or 1 in the calculation at the bottom. Now it's just a matter of readability - does it make sense to say max - min + minDefined? Perhaps! I'm warming up to this.

Since that particular variable will only hold a 0 or 1, I'm thinking of calling it bitValue or similar.

function rng(max, min) {
  var bitValue = min ? 1 : 0;
  var min = Number(min) || 0;
  var max = Number(max) || 1;
  if (min > max) { max = [min, min = max][0]; }
  if (max - min === 1) { return Math.random() + min; }
  else { return Math.floor(Math.random() * (max - min + bitValue)) + min; }
}

But, I'm liking the idea of adding a boolean value - we'll see :)

Nice! I like your solution, and of course, it's more readable than using a boolean value. That's not to say that boolean int values don't come in handy sometimes, in clever readability cases, but they're a minority.

In your situation, (max - min + bitValue) makes more sense because (max - min + true) just sounds weird to read as a human.

On the topic of readability, I think what you have now is pretty nice. If I were to make any comment, it would be that shorthand ternary operators tend to be a bit less readable than writing out the condition. I personally like them, and use them on my own projects, but I know a lot of software companies make it a rule to not use shorthands for debugging reasons. Because of that, I tend to avoid them on projects I know others may be looking through, especially if they're working on the code with me.

All great points. In the spirit of readability, here is the expanded version. Thanks again for sharing your thoughts.

function rng(max, min) {
      // optimized for only 1 lookup of var keyword
      var bitValue,
          min,
          max;

      // if min is defined, assume user wants an inclusive range
      if (min !== undefined) {
        bitValue = 1;
      } else {
        bitValue = 0;
      }

      // validating arguments or assigning default values
      min = Number(min) || 0;
      max = Number(max) || 1;

      // swap if necessary
      if (min > max) {
        max = [min, min = max][0];
      }

      // if range is 1, assume user wants a random floating-point value
      if (max - min === 1) {
        return Math.random() + min;
      }

      // if range > 1, assume user wants a random whole number value
      else {
        return Math.floor(Math.random() * (max - min + bitValue)) + min;
      }

      // todo: handle case where range < 1. Example: rng(0.2, 0.5)
}

Glad to have given some input! Looks great. Threads like this one are a nice change of pace sometimes.