Math.clamp method?
Remi Forax
forax at univ-mlv.fr
Wed Jan 25 14:15:13 UTC 2023
----- Original Message -----
> From: "Tagir Valeev" <amaembo at gmail.com>
> To: "core-libs-dev" <core-libs-dev at openjdk.org>
> Sent: Wednesday, January 25, 2023 2:41:41 PM
> Subject: Math.clamp method?
> Hello!
>
> Quite often it's necessary to clamp a numerical value to a given
> range, using the algorithm like this:
> int clampedValue = value > max ? max : value < min ? min : value;
> or probably
> int clampedValue = Math.max(min, Math.min(max, value));
> Some examples in wild: [1] [2]
>
> These "algorithms" are verbose and error-prone. E.g., many years ago
> Math.max and Math.min were mixed in Jenkins CI implementation (later
> fixed in [3]). Static analyzers like SonarLint even implement a rule
> to catch such kind of mistake [4], but it cannot statically find a
> mistake if max and min values are not constant.
>
> Having a library method for this algorithm will make the code more
> readable, and robust. Standard libraries of various languages tend to
> implement a function that encapsulates this algorithm. E.g., Kotlin
> coerseIn [5], C# Math.Clamp [6], Rust num::clamp [7].
>
> I hereby propose to add a similar method to Java Math class. The
> signatures could be:
> public static int clamp(int value, int min, int max)
> public static long clamp(long value, long min, long max)
> public static double clamp(double value, double min, double max)
> public static float clamp(float value, float min, float max)
>
> These methods should additionally check that min is not greater than
> max (throwing IllegalArgumentException). Probably IAE should be thrown
> as well if either min or max is NaN for floating point methods. It can
> be discussed what should happen if the value is NaN (I think returning
> NaN would be ok, but throwing an exception is also a possibility).
>
> I can post CSR and contribute the implementation if Core Library team
> members agree that it's a good idea.
I remember John Rose talking about something very similar to this proposal, there is maybe already a bug for it.
Given that the semantics of NaN is clearly defined for Math.max/min (if one of the values is NaN the result is NaN),
I don't believe we need a special case here for NaN.
The semantics should be, this is equivalent to execute
Math.max(min, Math.min(max, value))
So clamp(double) can be implemented using minsd and maxsd on x64, which is already what the VM does.
>
> With best regards,
> Tagir Valeev.
regards,
Rémi
>
> [1]
> https://github.com/moneymod/moneymod/blob/4d2c7f5be40dbf392e75/src/main/java/wtf/moneymod/client/impl/ui/click/buttons/settings/SliderButton.java#L71
> [2]
> https://github.com/androidthings/experiment-expression-flower/blob/f0fd6090e0df1659bad/code/app/src/main/java/com/example/androidthings/VideoProcessor.java#L559
> [3] https://github.com/jenkinsci/jenkins/commit/e00f99251e0b
> [4] https://rules.sonarsource.com/java/RSPEC-3065
> [5] https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.ranges/coerce-in.html
> [6] https://learn.microsoft.com/en-us/dotnet/api/system.math.clamp?view=net-7.0
> [7] https://docs.rs/num/0.2.1/num/fn.clamp.html
More information about the core-libs-dev
mailing list