-
Enhancement
-
Resolution: Fixed
-
P4
-
21
-
b10
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(long 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)
Note that the first overload accepts a long value, so it can be used also to safely narrow a long value to int without explicit cast.
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.
With best regards,
Tagir Valeev.
[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
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(long 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)
Note that the first overload accepts a long value, so it can be used also to safely narrow a long value to int without explicit cast.
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.
With best regards,
Tagir Valeev.
[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
- csr for
-
JDK-8301301 Add clamp() methods to java.lang.Math and to StrictMath
- Closed
- relates to
-
JDK-8302815 Use new Math.clamp method in core libraries
- Resolved
-
JDK-4466549 Add saturation/overflow integer arithmetic
- Closed