diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs
index 1395975ec..02a2e9ee5 100644
--- a/src/ImageSharp/Common/Helpers/ImageMaths.cs
+++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs
@@ -61,9 +61,6 @@ namespace SixLabors.ImageSharp
return x & (m - 1);
}
- [MethodImpl(InliningOptions.ShortMethod)]
- public static float Clamp(float x, float min, float max) => Math.Min(max, Math.Max(min, x));
-
///
/// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation.
///
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs
index fade8da79..737e62006 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs
@@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest)
{
- DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!");
+ DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
#if NETCOREAPP2_1
ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest);
@@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest)
{
- DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!");
+ DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
#if NETCOREAPP2_1
ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest);
@@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp
}
[MethodImpl(InliningOptions.ShortMethod)]
- private static byte ConvertToByte(float f) => (byte)ImageMaths.Clamp((f * 255f) + 0.5f, 0, 255f);
+ private static byte ConvertToByte(float f) => (byte)ComparableExtensions.Clamp((f * 255f) + 0.5f, 0, 255f);
[Conditional("DEBUG")]
private static void VerifyIsAvx2Compatible(string operation)
diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs
new file mode 100644
index 000000000..3b7dea095
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Runtime.CompilerServices;
+
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Running;
+
+namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
+{
+ public class ClampFloat
+ {
+ private readonly float min = -1.5f;
+ private readonly float max = 2.5f;
+ private static readonly float[] Values = { -10, -5, -3, -1.5f, -0.5f, 0f, 1f, 1.5f, 2.5f, 3, 10 };
+
+ [Benchmark(Baseline = true)]
+ public float UsingMathF()
+ {
+ float acc = 0;
+
+ for (int i = 0; i < Values.Length; i++)
+ {
+ acc += ClampUsingMathF(Values[i], this.min, this.max);
+ }
+
+ return acc;
+ }
+
+ [Benchmark]
+ public float UsingBranching()
+ {
+ float acc = 0;
+
+ for (int i = 0; i < Values.Length; i++)
+ {
+ acc += ClampUsingBranching(Values[i], this.min, this.max);
+ }
+
+ return acc;
+ }
+
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static float ClampUsingMathF(float x, float min, float max)
+ {
+ return Math.Min(max, Math.Max(min, x));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static float ClampUsingBranching(float x, float min, float max)
+ {
+ if (x >= max)
+ {
+ return max;
+ }
+
+ if (x <= min)
+ {
+ return min;
+ }
+
+ return x;
+ }
+
+ // RESULTS:
+ // Method | Mean | Error | StdDev | Scaled |
+ // --------------- |---------:|----------:|----------:|-------:|
+ // UsingMathF | 30.37 ns | 0.3764 ns | 0.3337 ns | 1.00 |
+ // UsingBranching | 18.66 ns | 0.1043 ns | 0.0871 ns | 0.61 |
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs
similarity index 98%
rename from tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs
rename to tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs
index d486cb2f3..6ce82ba11 100644
--- a/tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs
+++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs
@@ -10,7 +10,7 @@ using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
{
- public class Clamp
+ public class ClampInt32IntoByte
{
[Params(-1, 0, 255, 256)]
public int Value { get; set; }
diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs
index d8b1525be..75ef611a5 100644
--- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs
+++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs
@@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
[InlineData(10.1f, -0.1f, 10, 10f)]
public void Clamp(float x, float min, float max, float expected)
{
- float actual = ImageMaths.Clamp(x, min, max);
+ float actual = x.Clamp(min, max);
Assert.Equal(expected, actual);
}