What's the most elegant way to cap a number to a segment?

Let's say x, a and b are numbers. I need to limit x to the bounds of the segment [a, b].

In other words, I need a clamp function:

clamp(x) = max( a, min(x, b) )

Can anybody come up with a more readable version of this?


Solution 1:

The way you do it is pretty standard. You can define a utility clamp function:

/**
 * Returns a number whose value is limited to the given range.
 *
 * Example: limit the output of this computation to between 0 and 255
 * (x * 255).clamp(0, 255)
 *
 * @param {Number} min The lower boundary of the output range
 * @param {Number} max The upper boundary of the output range
 * @returns A number in the range [min, max]
 * @type Number
 */
Number.prototype.clamp = function(min, max) {
  return Math.min(Math.max(this, min), max);
};

(Although extending language built-ins is generally frowned upon)

Solution 2:

a less "Math" oriented approach, but should also work, this way, the < / > test is exposed (maybe more understandable than minimaxing) but it really depends on what you mean by "readable"

function clamp(num, min, max) {
  return num <= min 
    ? min 
    : num >= max 
      ? max 
      : num
}

Solution 3:

There's a proposal to add an addition to the built-in Math object to do this:

Math.clamp(x, lower, upper)

But note that as of today, it's a Stage 1 proposal. Until it gets widely supported (which is not guaranteed), you can use a polyfill.

Solution 4:

A simple way would be to use

Math.max(min, Math.min(number, max));

and you can obviously define a function that wraps this:

function clamp(number, min, max) {
  return Math.max(min, Math.min(number, max));
}

Originally this answer also added the function above to the global Math object, but that's a relic from a bygone era so it has been removed (thanks @Aurelio for the suggestion)