Math.min(Math.max(num, min), max)
281–290 of 291 posts
Re: Math.min(Math.max(num, min), max)
#282Earlier quoted context omitted.
Speaking only to JS is there any reason to write it any other way outside of being clever or as a lambda for singular use? I definitely prefer this version. (Assuming any necessary runtime checks are included for a given project)
There are many reasons to forego readability, especially when writing a library: performance, compatibility, requirements, interpreter/compiler optimizations or even cyclomatic complexity. In lodash's case it might even be all of the above, although I can't speak for the intentions of the authors since there are no comments to guide readers through the process. Note GP's link points to what looks like the v3 branch.…
clamp(null) returns 0
clamp(undefined) returns NaN
clamp(1, NaN, NaN) returns 0
clamp(1) returns 0
clamp(1, 5, NaN) returns 5
JavaScript is hard to write safe code for.
Re: Math.min(Math.max(num, min), max)
#283Re: Math.min(Math.max(num, min), max)
#284Earlier quoted context omitted.
Having a NaN at that point feels like a bug anyway, the solution is probably to check the arguments and throw an exception if NaN is provided (or use an input type that doesn't allow invalid values)
That would depend on what you do with the NaNs. For instance I have been using them extensively in time series data representation to denote a specific entry has no value - think of Saturday and stock/forex markets.
Recording the lack of a value is what null is for.
Re: Math.min(Math.max(num, min), max)
#285Earlier quoted context omitted.
It gets a bit confusing when the order of arguments is different depending on the library. For instance, with std it's std::clamp(val, min, max), but with Qt it's qBound(min, val, max) (for some reason I think the order of arguments in qBound is more logical).
The expression Math.min(Math.max(num, min), max) is symmetric in min and num , so it doesn’t matter whether you interchange min and num (or, for that matter, max and num , but that is harder to see from that way to define the ‘clamp’ function)
Re: Math.min(Math.max(num, min), max)
#286Earlier quoted context omitted.
That would depend on what you do with the NaNs. For instance I have been using them extensively in time series data representation to denote a specific entry has no value - think of Saturday and stock/forex markets.
That's not what NaN means. It means there is a value, and that value is... Check this out... "Not a Number". Recording the lack of a value is what null is for.
Re: Math.min(Math.max(num, min), max)
#287Earlier quoted context omitted.
That would depend on what you do with the NaNs. For instance I have been using them extensively in time series data representation to denote a specific entry has no value - think of Saturday and stock/forex markets.
That's not what NaN means. It means there is a value, and that value is... Check this out... "Not a Number". Recording the lack of a value is what null is for.
Re: Math.min(Math.max(num, min), max)
#288Earlier quoted context omitted.
If you are writing code that is clamping a lot of numbers, the GC churn from building a new array every time might be a problem.
Ideally the temporary array should optimise away.
https://repl.it/repls/GargantuanThistleLink
Result from sort: 3 in 0.9785124980007822s
Allocated 3000001 object(s)
Result from ternary: 3 in 0.3205206830025418s
Allocated 1 object(s)
Result from clamp: 3 in 0.5030354310001712s
Allocated 2 object(s)
Interestingly the ternary comparison is faster than clamp.Re: Math.min(Math.max(num, min), max)
#289Earlier quoted context omitted.
It gets a bit confusing when the order of arguments is different depending on the library. For instance, with std it's std::clamp(val, min, max), but with Qt it's qBound(min, val, max) (for some reason I think the order of arguments in qBound is more logical).
In Haskell, functions often take their arguments in the order that makes the most sense to partially apply. In this case, that would probably be clamp(min, max, val): supplying the first two arguments results in a reusable clamping function.
Re: Math.min(Math.max(num, min), max)
#290Earlier quoted context omitted.
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
Interestingly in your example, clang is able to resolve the first and the third line to the same assembler code.
I do wonder why it then isn't able to do that for the second line. Possibly because the CPU might have different flags set after processing the substraction?
But I'm not sure if your example is a good argument after I said I prefer less confusing code and you present an example which even confuses the compiler. ;-)