Live data from Hacker News

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

twitter.com

141–150 of 291 posts

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

#143

Earlier quoted context omitted.

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

Why sign though? I always write my sorts like this. .sort((a, b) => a - b)

Is there a better way to grab a reference to the subtraction operator?

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

#145
post #109
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)

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

So I tried a thing in python3.

    >>> max(float('nan'), 0)
    nan
    >>> max(0, float('nan'))
    0
Numpy works though

    >>> np.maximum(float('nan'), 0)
    nan
    >>> np.maximum(0, float('nan'))
    nan
Edit: Fixed numpy example.

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

#146

In languages I use there’s usually no need to write that code. C++/17 has std::clamp() in header. Modern C# has Math.Clamp() since .NET Core 2.0; too bad it’s not available in desktop edition of the runtime. HLSL has clamp() intrinsic function, and a special version saturate() to clamp into [ 0 .. +1 ] interval.

I had no idea .NET has Clamp() now. I’ve been writing something like the OP all this time ️

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

#147
I think the main hurdle is that we need to read this inside-out, which is something we face regularly trying to read nested function calls. I seriously believe pipe-like operators solve this problem cleanly.

In Elixir which does have the pipe `|>` this could be.

    number = number |> max(lower_bound) |> min(upper_bound)
Which IMO is quite elegant.

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

#149
post #28

I find that the fact that the functions min and max have the same name as the variables min and max increases cognitive load which makes it harder to think about it. I find the following easier to read : Math.min(Math.max(num, lower_bound), upper_bound)

[deleted]

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

#150
post #134
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)

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.
Post reply on HN