The below code supports specifying bounds in any order (i.e. bound1 <= bound2
, or bound2 <= bound1
). I've found this useful for clamping values calculated from linear equations (y=mx+b
) where the slope of the line can be increasing or decreasing.
I know: The code consists of five super-ugly conditional expression operators. The thing is, it works, and the tests below prove it. Feel free to add strictly unnecessary parentheses if you so desire.
You can easily create other overloads for other numeric types and basically copy/paste the tests.
Warning: Comparing floating point numbers is not simple. This code does not implement double
comparisons robustly. Use a floating point comparison library to replace the uses of comparison operators.
public static class MathExtensions
{
public static double Clamp(this double value, double bound1, double bound2)
{
return bound1 <= bound2 ? value <= bound1 ? bound1 : value >= bound2 ? bound2 : value : value <= bound2 ? bound2 : value >= bound1 ? bound1 : value;
}
}
xUnit/FluentAssertions tests:
public class MathExtensionsTests
{
[Theory]
[InlineData(0, 0, 0, 0)]
[InlineData(0, 0, 2, 0)]
[InlineData(-1, 0, 2, 0)]
[InlineData(1, 0, 2, 1)]
[InlineData(2, 0, 2, 2)]
[InlineData(3, 0, 2, 2)]
[InlineData(0, 2, 0, 0)]
[InlineData(-1, 2, 0, 0)]
[InlineData(1, 2, 0, 1)]
[InlineData(2, 2, 0, 2)]
[InlineData(3, 2, 0, 2)]
public void MustClamp(double value, double bound1, double bound2, double expectedValue)
{
value.Clamp(bound1, bound2).Should().Be(expectedValue);
}
}