From 436f56d912121fe2afb3c7ba4cfe37bd18f5ea69 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Wed, 29 Mar 2023 16:21:16 +0100 Subject: [PATCH] feat: add Saturate for floating point types (#60) --- CHANGELOG.md | 1 + X10D.Tests/src/Math/DecimalTests.cs | 18 ++++++++++++++++++ X10D.Tests/src/Math/DoubleTests.cs | 18 ++++++++++++++++++ X10D.Tests/src/Math/SingleTests.cs | 18 ++++++++++++++++++ X10D/src/Math/DecimalExtensions.cs | 17 +++++++++++++++++ X10D/src/Math/DoubleExtensions.cs | 17 +++++++++++++++++ X10D/src/Math/SingleExtensions.cs | 17 +++++++++++++++++ 7 files changed, 106 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a64ea8..33fb935 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - X10D: Added `ReadOnlySpan.Split(T)`. - X10D: Added `ReadOnlySpan.Split(ReadOnlySpan)`. - X10D: Added `RoundUpToPowerOf2()` for built-in integer types. +- X10D: Added `Saturate()` for built-in floating-point types. - X10D: Added `Size.ToPoint()`. - X10D: Added `Size.ToPointF()`. - X10D: Added `Size.ToVector2()`. diff --git a/X10D.Tests/src/Math/DecimalTests.cs b/X10D.Tests/src/Math/DecimalTests.cs index b84b1cf..dadf650 100644 --- a/X10D.Tests/src/Math/DecimalTests.cs +++ b/X10D.Tests/src/Math/DecimalTests.cs @@ -82,6 +82,24 @@ public class DecimalTests Assert.AreEqual(10.0m, 7.5m.Round(5)); } + [TestMethod] + public void Saturate_ShouldClampValueTo1_GivenGreaterThan1() + { + Assert.AreEqual(1.0m, 1.5m.Saturate(), 1e-6m); + } + + [TestMethod] + public void Saturate_ShouldClampValueTo0_GivenLessThan0() + { + Assert.AreEqual(0.0m, (-0.5m).Saturate(), 1e-6m); + } + + [TestMethod] + public void Saturate_ShouldReturnValue_GivenValueBetween0And1() + { + Assert.AreEqual(0.5m, 0.5m.Saturate(), 1e-6m); + } + [TestMethod] public void Sign_ShouldBeMinus1_GivenNegative() { diff --git a/X10D.Tests/src/Math/DoubleTests.cs b/X10D.Tests/src/Math/DoubleTests.cs index 96034bc..f5ebe01 100644 --- a/X10D.Tests/src/Math/DoubleTests.cs +++ b/X10D.Tests/src/Math/DoubleTests.cs @@ -117,6 +117,24 @@ public class DoubleTests Assert.AreEqual(10.0, 7.5.Round(5), 1e-6); } + [TestMethod] + public void Saturate_ShouldClampValueTo1_GivenGreaterThan1() + { + Assert.AreEqual(1.0, 1.5.Saturate(), 1e-6); + } + + [TestMethod] + public void Saturate_ShouldClampValueTo0_GivenLessThan0() + { + Assert.AreEqual(0.0, (-0.5).Saturate(), 1e-6); + } + + [TestMethod] + public void Saturate_ShouldReturnValue_GivenValueBetween0And1() + { + Assert.AreEqual(0.5, 0.5.Saturate(), 1e-6); + } + [TestMethod] public void Sign_ShouldBeMinus1_GivenNegative() { diff --git a/X10D.Tests/src/Math/SingleTests.cs b/X10D.Tests/src/Math/SingleTests.cs index 82c2c0d..2deb0ca 100644 --- a/X10D.Tests/src/Math/SingleTests.cs +++ b/X10D.Tests/src/Math/SingleTests.cs @@ -117,6 +117,24 @@ public class SingleTests Assert.AreEqual(10.0f, 7.5f.Round(5), 1e-6f); } + [TestMethod] + public void Saturate_ShouldClampValueTo1_GivenGreaterThan1() + { + Assert.AreEqual(1.0f, 1.5f.Saturate(), 1e-6f); + } + + [TestMethod] + public void Saturate_ShouldClampValueTo0_GivenLessThan0() + { + Assert.AreEqual(0.0f, (-0.5f).Saturate(), 1e-6f); + } + + [TestMethod] + public void Saturate_ShouldReturnValue_GivenValueBetween0And1() + { + Assert.AreEqual(0.5f, 0.5f.Saturate(), 1e-6f); + } + [TestMethod] public void Sign_ShouldBeMinus1_GivenNegative() { diff --git a/X10D/src/Math/DecimalExtensions.cs b/X10D/src/Math/DecimalExtensions.cs index 094d4ef..951355a 100644 --- a/X10D/src/Math/DecimalExtensions.cs +++ b/X10D/src/Math/DecimalExtensions.cs @@ -94,6 +94,23 @@ public static class DecimalExtensions return System.Math.Round(value / nearest) * nearest; } + /// + /// Saturates this decimal number. + /// + /// The value to saturate. + /// The saturated value. + /// This method clamps between 0 and 1. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static decimal Saturate(this decimal value) + { + return System.Math.Clamp(value, 0.0m, 1.0m); + } + /// /// Returns an integer that indicates the sign of this decimal number. /// diff --git a/X10D/src/Math/DoubleExtensions.cs b/X10D/src/Math/DoubleExtensions.cs index e1d55c3..58d83ca 100644 --- a/X10D/src/Math/DoubleExtensions.cs +++ b/X10D/src/Math/DoubleExtensions.cs @@ -312,6 +312,23 @@ public static class DoubleExtensions return System.Math.Round(value / nearest) * nearest; } + /// + /// Saturates this double-precision floating-point number. + /// + /// The value to saturate. + /// The saturated value. + /// This method clamps between 0 and 1. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static double Saturate(this double value) + { + return System.Math.Clamp(value, 0.0, 1.0); + } + /// /// Returns the sine of the specified angle. /// diff --git a/X10D/src/Math/SingleExtensions.cs b/X10D/src/Math/SingleExtensions.cs index 02f46c7..1b180c9 100644 --- a/X10D/src/Math/SingleExtensions.cs +++ b/X10D/src/Math/SingleExtensions.cs @@ -312,6 +312,23 @@ public static class SingleExtensions return MathF.Round(value / nearest) * nearest; } + /// + /// Saturates this single-precision floating-point number. + /// + /// The value to saturate. + /// The saturated value. + /// This method clamps between 0 and 1. + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static float Saturate(this float value) + { + return System.Math.Clamp(value, 0.0f, 1.0f); + } + /// /// Returns an integer that indicates the sign of this single-precision floating-point number. ///