Is it possible to make a clamp function shorter than a ternary in JS?

22

1

Imagine this short function to clamp a number between 0 and 255:

c = n => n > 0 ? n < 255 ? n : 255 : 0

Is this the shortest possible version of a clamp function with JavaScript (without ES.Next features)?

P.S: Not sure if it's relevant but, the 0 and 255 are not random, the idea is to clamp a number as an 8-bit unsigned integer.

rfgamaral

Posted 2019-03-05T23:03:04.353

Reputation: 323

2Hi and welcome to PPCG! Just to be clear, any answer you receive here will not necessarily be a good idea to use in anything except for code golfing. Aside from that, if you care about what version / environment it has to work in you might want to specify it. – FryAmTheEggman – 2019-03-05T23:09:33.627

1Oh, I'm well aware. I've updated the question a bit. Thank you :) – rfgamaral – 2019-03-05T23:12:57.743

Shouldn't you at least remove all the spaces? – Adám – 2019-03-05T23:14:56.817

2I don't know JS, but one way to clamp is to sort [0,n,255] and take the middle element -- might that be shorter? – xnor – 2019-03-05T23:26:54.733

1

@xnor Unfortunately, the JS sort() method uses a lexicographical comparison by default, so that would require an explicit callback. (Something like that.)

– Arnauld – 2019-03-05T23:30:35.203

5@Arnauld Wow, that's pretty silly. But it looks like it would be longer even if the sort was numerical. – xnor – 2019-03-05T23:34:56.153

I can't imagine a case where a length 1 array would be golfier than the approaches suggested, but just out of interest, JavaScript has built in support for clamped 8 bit unsigned ints: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray

– trichoplax – 2019-03-08T18:29:03.863

Answers

23

20 bytes

For reference, this is the original version without whitespace and without naming the function:

n=>n>0?n<255?n:255:0

Try it online!


19 bytes

We can save a byte by inverting the logic of the ternary tests and using n>>8 to test whether \$n\$ is greater than \$255\$. Because of the bitwise operation, this will however fail for \$n\ge 2^{32}\$.

n=>n<0?0:n>>8?255:n

Try it online!


19 bytes

This one returns \$false\$ instead of \$0\$ but works for \$n\ge 2^{32}\$.

n=>n>255?255:n>0&&n

Try it online!


18 bytes

By combining both versions above, we end up with a function that works for \$256-2^{32}\le n<2^{32}\$ and returns \$false\$ for \$n<0\$.

n=>n>>8?n>0&&255:n

Try it online!

Commented

n =>          // n = input number
  n >> 8 ?    // if n is greater than 255 or n is negative:
    n > 0 &&  //   return false if n is negative
    255       //   or 255 otherwise
  :           // else:
    n         //   return n unchanged

(This is a fixed revision of the code proposed by @ValueInk in the comments.)


17 bytes

We can go a step further by limiting the valid input range to \$-2^{24}< n\le 2^{24}\$:

n=>n>>8?-n>>>24:n

Try it online!

Commented

n =>          // n = input number
  n >> 8 ?    // if n is greater than 255 or n is negative:
    -n >>> 24 //   non-arithmetic right-shift of -n by 24 positions
  :           // else:
    n         //   return n unchanged

Arnauld

Posted 2019-03-05T23:03:04.353

Reputation: 111 334

Why stop there? If you're extremely liberal with what counts as a 0 (as JavaScript tends to do) you can always go for n=>n>>8?255:n>0&&n for 18 bytes, since false can be coerced to 0 and this will make all negative numbers evaluate to false – Value Ink – 2019-03-05T23:39:18.440

1@ValueInk If you don't test $n<0$ beforhand, n>>8 will be truthy for any negative input. – Arnauld – 2019-03-05T23:41:39.270

Very nice, thank you so much! – rfgamaral – 2019-03-06T10:21:23.400