diff --git a/UnitsNet.Tests/UnitMathTests.cs b/UnitsNet.Tests/UnitMathTests.cs index 014c8c65ea..67509044fd 100644 --- a/UnitsNet.Tests/UnitMathTests.cs +++ b/UnitsNet.Tests/UnitMathTests.cs @@ -156,26 +156,40 @@ public void SumOfLengthsWithSelectorCalculatesCorrectly() } [Fact] - public void ClampCalculatesCorrectly() + public void Clamp_ReturnsValue_WhenWithinBounds() { var min = Length.FromMeters(-1); var max = Length.FromCentimeters(150); - - var value1 = Length.FromMillimeters(33); - - Length clampedValue = UnitMath.Clamp(value1, min, max); + var value = Length.FromMillimeters(33); + + Length clampedValue = UnitMath.Clamp(value, min, max); + Assert.Equal(33, clampedValue.Value); Assert.Equal(LengthUnit.Millimeter, clampedValue.Unit); + } - var value2 = Length.FromMillimeters(-1500); - - Length clampedMin = UnitMath.Clamp(value2, min, max); + [Fact] + public void Clamp_ReturnsMinAsValueUnit_WhenValueIsBelowMin() + { + var min = Length.FromMeters(-1); + var max = Length.FromCentimeters(150); + var value = Length.FromMillimeters(-1500); + + Length clampedMin = UnitMath.Clamp(value, min, max); + Assert.Equal(-1000, clampedMin.Value); Assert.Equal(LengthUnit.Millimeter, clampedMin.Unit); + } - var value3 = Length.FromMillimeters(2000); - - Length clampedMax = UnitMath.Clamp(value3, min, max); + [Fact] + public void Clamp_ReturnsMaxAsValueUnit_WhenValueIsAboveMax() + { + var min = Length.FromMeters(-1); + var max = Length.FromCentimeters(150); + var value = Length.FromMillimeters(2000); + + Length clampedMax = UnitMath.Clamp(value, min, max); + Assert.Equal(1500, clampedMax.Value); Assert.Equal(LengthUnit.Millimeter, clampedMax.Unit); } diff --git a/UnitsNet/UnitMath.cs b/UnitsNet/UnitMath.cs index 38c7246201..a6fb77465b 100644 --- a/UnitsNet/UnitMath.cs +++ b/UnitsNet/UnitMath.cs @@ -1,76 +1,96 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; +namespace UnitsNet; -namespace UnitsNet +/// +/// Extension methods for common math operations. +/// +public static class UnitMath { + /// Returns the smaller of two values. + /// The type of quantities to compare. + /// The first of two values to compare. + /// The second of two values to compare. + /// Parameter or , whichever is smaller. + public static TQuantity Min(TQuantity val1, TQuantity val2) + where TQuantity : IQuantity, IComparable + { + return val1.CompareTo(val2) == 1 ? val2 : val1; + } + + /// Returns the larger of two values. + /// The type of quantities to compare. + /// The first of two values to compare. + /// The second of two values to compare. + /// Parameter or , whichever is larger. + public static TQuantity Max(TQuantity val1, TQuantity val2) + where TQuantity : IQuantity, IComparable + { + return val1.CompareTo(val2) == -1 ? val2 : val1; + } + /// - /// A set of extension methods for some of the most common Math operations, such as Min, Max, Sum and Average + /// Clamps the specified to the inclusive range defined by and + /// . /// - public static class UnitMath + /// + /// The type of the quantity, which must implement and + /// . + /// + /// The value to clamp. + /// The minimum allowable value. + /// The maximum allowable value. + /// + /// The clamped value: + /// + /// + /// + /// if it lies within the range [, + /// ]. + /// + /// + /// + /// + /// (converted to value.Unit) if is less than + /// . + /// + /// + /// + /// + /// (converted to value.Unit) if is greater than + /// . + /// + /// + /// + /// + /// + /// Thrown if is greater than . + /// + public static TQuantity Clamp(TQuantity value, TQuantity min, TQuantity max) + where TQuantity : IQuantityOfType, IComparable { - /// Returns the smaller of two values. - /// The type of quantities to compare. - /// The first of two values to compare. - /// The second of two values to compare. - /// Parameter or , whichever is smaller. - public static TQuantity Min(TQuantity val1, TQuantity val2) - where TQuantity : IQuantity, IComparable + UnitKey unitKey = value.UnitKey; +#if NET + TQuantity minValue = TQuantity.Create(min.As(unitKey), unitKey); + TQuantity maxValue = TQuantity.Create(max.As(unitKey), unitKey); +#else + TQuantity minValue = value.QuantityInfo.Create(min.As(unitKey), unitKey); + TQuantity maxValue = value.QuantityInfo.Create(max.As(unitKey), unitKey); +#endif + + if (minValue.CompareTo(maxValue) > 0) { - return val1.CompareTo(val2) == 1 ? val2 : val1; + throw new ArgumentException($"min ({min}) cannot be greater than max ({max})", nameof(min)); } - /// Returns the larger of two values. - /// The type of quantities to compare. - /// The first of two values to compare. - /// The second of two values to compare. - /// Parameter or , whichever is larger. - public static TQuantity Max(TQuantity val1, TQuantity val2) - where TQuantity : IQuantity, IComparable + if (value.CompareTo(minValue) < 0) { - return val1.CompareTo(val2) == -1 ? val2 : val1; + return minValue; } - - /// Returns clamped to the inclusive range of and . - /// The value to be clamped. - /// The lower bound of the result. - /// The upper bound of the result. - /// - /// if . - /// - /// -or- - /// - /// (converted to value.Unit) if < . - /// - /// -or- - /// - /// (converted to value.Unit) if < . - /// - /// - /// cannot be greater than . - /// - public static TQuantity Clamp(TQuantity value, TQuantity min, TQuantity max) where TQuantity : IComparable, IQuantity - { - var minValue = (TQuantity)min.ToUnit(value.Unit); - var maxValue = (TQuantity)max.ToUnit(value.Unit); - - if (minValue.CompareTo(maxValue) > 0) - { - throw new ArgumentException($"min ({min}) cannot be greater than max ({max})", nameof(min)); - } - - if (value.CompareTo(minValue) < 0) - { - return minValue; - } - if (value.CompareTo(maxValue) > 0) - { - return maxValue; - } - - return value; + if (value.CompareTo(maxValue) > 0) + { + return maxValue; } + + return value; } }