News for hackers. Stuff that matters.
Re:Math.min(Math.max(num, min), max) by tobr on Thursday August 20, 2020 @10:14AM (#24223458)

  [min, num, max].sort()[1]
Re:Math.min(Math.max(num, min), max) by tosh on Thursday August 20, 2020 @10:19AM (#24223514)
sort() on JavaScript arrays sorts alphabetically (unless you pass a compareFunction)

https://stackoverflow.com/questions/21019902/why-cant-javasc...

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Re:Math.min(Math.max(num, min), max) by yesbabyyes on Thursday August 20, 2020 @10:57AM (#24223944)
Good point, for those who need to implement a slick compareFunction for numbers, Math.sign is great:

  [min, num, max].sort((a, b) => Math.sign(a - b))[1]
An entirely different alternative is poor man's match:

  switch (true) {
  case num > max: return max;
  case num < min: return min;
  default: return num;
  }
Re:Math.min(Math.max(num, min), max) by recursive on Thursday August 20, 2020 @12:50PM (#24225338)
Why sign though? I always write my sorts like this.

    .sort((a, b) => a - b)
Re:Math.min(Math.max(num, min), max) by saagarjha on Thursday August 20, 2020 @02:38PM (#24226859)
Is there a better way to grab a reference to the subtraction operator?
Re:Math.min(Math.max(num, min), max) by recursive on Thursday August 20, 2020 @03:39PM (#24227796)
I assume you're referring to a point-free reference.

Only by defining a `const subtract = (a, b) => a - b;`, which isn't really point-free.

Or by using a different language.

Re:Math.min(Math.max(num, min), max) by tgb on Thursday August 20, 2020 @10:50AM (#24223866)
Wait, really? I just had to double-check my one JS project for bugs and either I used to know this gotcha or I got lucky. My sort()-ing needed to handle NaNs carefully so I was already using custom comparators.
Re:Math.min(Math.max(num, min), max) by TimTheTinker on Thursday August 20, 2020 @01:18PM (#24225767)
"lexicographically" is a better descriptor than "alphabetically", since it's sorting by UTF-8 code point value.
Re:Math.min(Math.max(num, min), max) by edflsafoiewq on Thursday August 20, 2020 @02:01PM (#24226341)
It sorts by UTF-16 code unit.
Re:Math.min(Math.max(num, min), max) by TimTheTinker on Thursday August 20, 2020 @02:34PM (#24226808)
Of course, my bad.
Re:Math.min(Math.max(num, min), max) by tobr on Thursday August 20, 2020 @10:22AM (#24223551)
Very good point. I thought of it more as pseudocode.
Re:Math.min(Math.max(num, min), max) by tosh on Thursday August 20, 2020 @10:26AM (#24223602)
imho a very elegant solution and probably works in most languages, I was surprised by JavaScript's behaviour myself
Re:Math.min(Math.max(num, min), max) by 1-more on Thursday August 20, 2020 @11:24AM (#24224200)
For a real fun headscratcher consider [ '9', '10', '11', '12', '13' ].map(parseInt)
Re:Math.min(Math.max(num, min), max) by yboris on Thursday August 20, 2020 @12:02PM (#24224638)
Thank you for this exercise! I figured it out!

[ROT 13] spoiler: cnefrVag frpbaq nethzrag vf onfr, znc frpbaq nethzrag vf vaqrk va neenl. 10 vf gur frpbaq nethzrag, vaqrk 1. cnefrVag(10, 1) unf vyyrtny onfr

[0] https://rot13.com/

Re:Math.min(Math.max(num, min), max) by unoti on Thursday August 20, 2020 @10:31AM (#24223657)
[min, num, max].sort()[1]

I really love this! I’m not sure whether to laugh, cry, or applaud, but I love how it makes me feel all those emotions at the same time.

Re:Math.min(Math.max(num, min), max) by city41 on Thursday August 20, 2020 @01:41PM (#24226065)
I also think the fact it doesn't work in JS (due to sort defaulting to alphabetical sort) brings in even more appropriate emotions.
Re:Math.min(Math.max(num, min), max) by sanbor on Thursday August 20, 2020 @05:12PM (#24229046)

    [10, 2, 100].sort()[1] //returns 100
Re:Math.min(Math.max(num, min), max) by gridlockd on Thursday August 20, 2020 @12:58PM (#24225478)
This is why computers are slow.
Re:Math.min(Math.max(num, min), max) by saagarjha on Thursday August 20, 2020 @03:52PM (#24227979)
I was curious how slow this would be, and here is what JavaScriptCore made of this code:

  function clamp(n, min, max) {
      return [min, n, max].sort((a, b) => a - b)[1];
  }
  
  for (var i = 0; i < 10000000; i++) {
      clamp(Math.random() | 0, Math.random() | 0, Math.random() | 0);
  }
However, I was pretty disappointed when it seemed to be calling sort each time :( Perhaps I profiled it incorrectly? jsc's profiling data shows that it never hit FTL and nothing ever got inlined. The bytecode for DFG and Baseline is identical:

  Compilation clamp#CChm91-1-Baseline:
        arg0: predicting OtherObj
        arg1: predicting BoolInt32
        arg2: predicting BoolInt32
        arg3: predicting BoolInt32
          [   0] enter              
          [   1] get_scope          loc4
          [   3] mov                loc5, loc4
          [   6] check_traps        
          [   7] mov                loc11, arg2
          [  10] mov                loc12, arg1
          [  13] mov                loc13, arg3
          [  16] new_array          loc10, loc11, 3, 3
          [  22] get_by_id          loc7, loc10, 0
          [  27] new_func_exp       loc9, loc4, 0
          [  31] call               loc7, loc7, 2, 16
          [  37] get_by_val         loc6, loc7, Int32: 1(const0)
          [  42] ret                loc6

  Compilation clamp#CChm91-2-DFG:
        arg0: predicting OtherObj
        arg1: predicting BoolInt32
        arg2: predicting BoolInt32
        arg3: predicting BoolInt32
          [   0] enter              
          [   1] get_scope          loc4
          [   3] mov                loc5, loc4
          [   6] check_traps        
          [   7] mov                loc11, arg2
          [  10] mov                loc12, arg1
          [  13] mov                loc13, arg3
          [  16] new_array          loc10, loc11, 3, 3
          [  22] get_by_id          loc7, loc10, 0
          [  27] new_func_exp       loc9, loc4, 0
          [  31] call               loc7, loc7, 2, 16
          [  37] get_by_val         loc6, loc7, Int32: 1(const0)
          [  42] ret                loc6
Re:Math.min(Math.max(num, min), max) by garmaine on Thursday August 20, 2020 @06:42PM (#24229870)
Dude, you are generating random numbers inside the loop. That is going to dominate runtime.
Re:Math.min(Math.max(num, min), max) by saagarjha on Thursday August 20, 2020 @06:56PM (#24229984)
I'm not testing runtime, though, I'm testing whether clamp gets optimized.
Re:Math.min(Math.max(num, min), max) by secondcoming on Thursday August 20, 2020 @01:39PM (#24226049)
No. Just things written by web devs.

(Shots fired)

Re:Math.min(Math.max(num, min), max) by vortico on Thursday August 20, 2020 @11:20AM (#24224169)
This is also nice because it gracefully handles the case where `max < min`.
Re:Math.min(Math.max(num, min), max) by rags2riches on Thursday August 20, 2020 @12:57PM (#24225455)
It's not always graceful to say that 1 is both less than 0 and greater than 2.
Re:Math.min(Math.max(num, min), max) by vortico on Thursday August 20, 2020 @01:24PM (#24225847)
Not sure what you mean. If I want to clamp 1 between 2 and 0, the most reasonable answer is 1, which is correctly returned by this code.
Re:Math.min(Math.max(num, min), max) by resu_nimda on Thursday August 20, 2020 @02:32PM (#24226767)
He's saying that, if you have explicitly defined a max and min such that max < min, it is not graceful for the computer to produce a result as though those values were swapped. In other words, garbage in should produce garbage out.

The array implementation sidesteps this by not semantically defining a max and min, instead sorting three arbitrary numbers.

Re:Math.min(Math.max(num, min), max) by tobr on Thursday August 20, 2020 @03:26PM (#24227593)
In practice “max” and “min” often aren’t conceptually important for a clamp function. It’s more that you want to keep a value within a range, which is defined by two end points in arbitrary order.

If that is the version of clamp you need, the sort based solution reveals something profound and unexpected: it’s not just the two end points of the range that are equivalent, but all three numbers. Keeping value A between B and C is the same as keeping B between A and C or C between A and B. It’s completely arbitrary which pair you consider to be a range.

Re:Math.min(Math.max(num, min), max) by vortico on Thursday August 20, 2020 @03:00PM (#24227236)
Why do you prefer to leave undefined behavior?
Re:Math.min(Math.max(num, min), max) by resu_nimda on Thursday August 20, 2020 @03:53PM (#24228001)
I'm not sure what you mean. The behavior of the max() and min() functions is perfectly well defined. The terms "maximum" and "minimum" are well defined. If I were using those terms I would likely consider the case where max < min to be an error, or have some other meaning, like an empty range.

If I wanted it to automatically flip the values to ensure a sensible range is defined, I would probably use "a" and "b" or "endpoint1" and "endpoint2" or something, because "max" has now become "max or min," which is not the same.

Re:Math.min(Math.max(num, min), max) by seanwilson on Thursday August 20, 2020 @03:10PM (#24227381)
It's cute but if you used this in an innerloop (like a game, simulation or graphics code where 'clamp' is used often), it'll generate a ton of garbage as well as potential slowdown for no good reason.
Re:Math.min(Math.max(num, min), max) by tobr on Thursday August 20, 2020 @03:31PM (#24227667)
This should be completely obvious, but largely irrelevant to the topic at hand. The linked tweet talks about how difficult it is to remember the order of the terms when you implement clamp a certain way; I just wanted to point out that with a different solution, the order surprisingly doesn’t matter at all.
Re:Math.min(Math.max(num, min), max) by seanwilson on Thursday August 20, 2020 @03:42PM (#24227842)
I don't think it's obvious though - many people have never optimised for garbage collection so I thought it was worth pointing out.

I still found your approach interesting and it's rare there's a perfect approach so don't take it to heart.

Re:Math.min(Math.max(num, min), max) by throwawaw on Thursday August 20, 2020 @11:21AM (#24224178)
I love this one.
Re:Math.min(Math.max(num, min), max) by agumonkey on Thursday August 20, 2020 @01:05PM (#24225591)
never thought of clamp as precompiled sort