Live data from Hacker News

Math.min(Math.max(num, min), max)

twitter.com

261–270 of 291 posts

Re: Math.min(Math.max(num, min), max)

#261

Earlier quoted context omitted.

> in desktop edition of the runtime huh?

MS .NET framework. Unfortunately, for the last couple years it lags behind .NET core. Even 2 years old .NET core 2.1 is better in some regards than the latest desktop version 4.8.

.NET Framework is now in maintenance mode because they're transitioning to .NET Core (soon called as .NET 5). I would call .NET Framework as Legacy edition rather than Desktop edition

Re: Math.min(Math.max(num, min), max)

#262

Earlier quoted context omitted.

Your two functions are not equivalent. std::fmax handles NaN, but std::clamp does not.

Depends on how the comparisons are ordered. Some of the orderings I've seen in here do respect NaN by virtue of `x > upper_bound` comparing false if either x or upper_bound are NaN.

Both functions are defined how they handle NaN by the standard. There is no ordering or implementation ambiguity by design.

Re: Math.min(Math.max(num, min), max)

#263
post #12
post #6

> it takes me ages to convince myself this implementation is correct It would take them less time to convince themself if they switched min and num to put the values in proper semantic order: min Math.min(Math.max(min, num), max)

That still leaves the order of Math.min and Math.max undecided and will probably not help much if you get easily confused by the visuals of this code. I never thought about it but of course there must be code tongue twisters (or more correctly, brain twisters). Thinking about it, I would probably go with a less confusing implementation. Terse code is hard to read and the compiler is likely clever enough to choose the…

> and the compiler is likely clever enough to choose the best implementation anyway.

Not in my experience. The compiler is likely to be able to do something decent to it, but it'll probably be different.

Consider the following snippets. For unsigned integers they're all equivalent (and return the max of x and m), but gcc with a wide range of flags can't recognize them as identical.

  (x=m) * x

  (x

Re: Math.min(Math.max(num, min), max)

#264
post #75

Earlier quoted context omitted.

Easy to remember, but may take some time to grasp: Arrays.sort( {lower_bound, num, upper_bound} )[1]; Next challenge: teach the optimizer to make that almost as fast as the min/max way ;-) (You can’t reduce it to the min/max call because it also works if you accidentally pass a lower bound that’s larger than the upper bound. Worst-case, the above takes 3 comparisons, unless at least two of the inputs are constants)

Beware that in JavaScript, the language that this tweet is about, the sort function sorts alphabetically by default. [100, 10, 11].sort()[1] === 100

Wait, really?

BRB, just checking some code…

Re: Math.min(Math.max(num, min), max)

#265
post #134

Earlier quoted context omitted.

You know what's great about that? The order of the arguments doesn't matter. So all the debate about "should it be num, min, max or min, num, max"- your solution does not care. Put them in any order you like! You've redefined the problem from clamping a given value into picking the middle value from 3. This is a lovely way to re-interpret it.

Well, the order of the arguments does matter. Sorting three values requires 2.67 comparisons where clamping a value between two other values requires exactly 2. There are plenty of contexts where cleverly avoiding a problem by doing 33% more work isn't viewed as desirable.

True, but I think there are more situations where minimizing the chance of programmer error, now or in the future, is more important than a micro-optimization that will never matter. All depends on context.

Re: Math.min(Math.max(num, min), max)

#266
For maximum readability, you could also go for

  (min + ((num + max - Math.abs(num - max)) / 2) + Math.abs(min - ((num + max - Math.abs(num - max)) / 2))) / 2
Since

  min(a, b) = (a + b - |a - b|) / 2
and

  max(a, b) = (a + b + |a - b|) / 2

Re: Math.min(Math.max(num, min), max)

#267

>[...] it takes me ages to convince myself this implementation is correct. Is that supposed to be difficult? Not trying to be snarky, I'm honestly surprised, do people actually struggle with this? Googlers in particular?

Do people actually struggle with not being snarky to the point where they have to explicitly say that, and still come across as snarky?

Re: Math.min(Math.max(num, min), max)

#268
post #109

Earlier quoted context omitted.

this doesn't work for NaN, e.g {0d, Double.NaN, 1d} returns 1d.

Does NaN have an "order" in the set of reals or integers or whatever? I would have no idea what to expect from `min(NaN, x)` or max same. But is it specified by an IEEE standard or something?

The only reason I know what to expect is because Suckerpinch on YouTube made a video in which he managed to define a logic system using NaN and +∞, and does so by abusing min and max, among other expressions:

https://youtu.be/5TFDG-y-EHs

Re: Math.min(Math.max(num, min), max)

#269

OPs implementation requires 2 comparisons. I think this C expression is clearer, and will sometimes use 1 comparison: num max ? max : num

Branching is the expensive part, not comparisons.

This is 3 branches. The Math method ends up with 4.

This is one of those cases where I think it is much more readable to just write the code than to puzzle over what Math.min(Math.max(min, num), max); might be doing.

    if (num  max)
      return max;
    return num;
That's how I'd write it. May not be super terse, but anyone that stumbles on this will know precisely what's happening without needing to take a few seconds to puzzle things out.

Re: Math.min(Math.max(num, min), max)

#270

Earlier quoted context omitted.

Absolutely. With the above implementation, I can see exactly what's going on, with the others, I'm trying to work out potential edge cases.

I prefer the min/max-based definition for the same reason: Its easier to work out the edge cases around NaN and comparisons against NaN.

NaN always returns false on comparisons. So seems pretty straight forward that this would return NaN if NaN is passed in.

That doesn't seem unreasonable. (In fact, that's what happens with the min/max approach).

Post reply on HN