From 1f86ef2c598a19d2baabd2cdcd0364d9fe6512a3 Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Mon, 27 Mar 2023 01:12:39 +0200 Subject: [PATCH] MathUtils.IsPow2 & MathUtils.GetPow2Shift performance improvements. --- Recyclable.Collections/MathUtils.cs | 7 ++- Recyclable.CollectionsTests/MathUtilsTests.cs | 63 +++++++++++++++++-- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/Recyclable.Collections/MathUtils.cs b/Recyclable.Collections/MathUtils.cs index 98b63c0..40f2141 100644 --- a/Recyclable.Collections/MathUtils.cs +++ b/Recyclable.Collections/MathUtils.cs @@ -1,4 +1,5 @@ -using System.Runtime.CompilerServices; +using System.Numerics; +using System.Runtime.CompilerServices; namespace Recyclable.Collections { @@ -13,10 +14,10 @@ namespace Recyclable.Collections }; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsPow2(int value) => Array.BinarySearch(Pow2, value) >= 0; + public static bool IsPow2(long value) => (value != 0) && ((value & (value - 1)) == 0); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetPow2Shift(int value) => Array.BinarySearch(Pow2, value); + public static int GetPow2Shift(long value) => BitOperations.IsPow2(value) ? 63 - BitOperations.LeadingZeroCount((ulong)value) : -1; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long DivMod(long number, int divider, out long remainder) diff --git a/Recyclable.CollectionsTests/MathUtilsTests.cs b/Recyclable.CollectionsTests/MathUtilsTests.cs index 40c9362..dd8e625 100644 --- a/Recyclable.CollectionsTests/MathUtilsTests.cs +++ b/Recyclable.CollectionsTests/MathUtilsTests.cs @@ -1,10 +1,5 @@ using FluentAssertions; using Recyclable.Collections; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Recyclable.CollectionsTests { @@ -28,5 +23,63 @@ namespace Recyclable.CollectionsTests _ = actualRemainder.Should().Be(expectedRemainder); } } + + [Theory] + [InlineData(0, false)] + [InlineData(1, true)] + [InlineData(2, true)] + [InlineData(3, false)] + [InlineData(4, true)] + [InlineData(5, false)] + [InlineData(8, true)] + [InlineData(16, true)] + [InlineData(20, false)] + [InlineData(32, true)] + [InlineData(64, true)] + [InlineData(128, true)] + [InlineData(256, true)] + [InlineData(512, true)] + [InlineData(1024, true)] + [InlineData(2048, true)] + [InlineData(4096, true)] + [InlineData(8192, true)] + [InlineData(16384, true)] + [InlineData(32768, true)] + [InlineData(65536, true)] + [InlineData(131072, true)] + [InlineData(262144, true)] + [InlineData(524288, true)] + [InlineData(1048576, true)] + [InlineData(2097152, true)] + [InlineData(4194304, true)] + [InlineData(8388608, true)] + [InlineData(16777216, true)] + [InlineData(33554432, true)] + [InlineData(67108864, true)] + [InlineData(134217728, true)] + [InlineData(268435456, true)] + [InlineData(536870912, true)] + [InlineData(1073741824, true)] + [InlineData(2147483648, true)] + [InlineData(2147483649, false)] + [InlineData(4294967296, true)] + public void IsPow2(long testNumber, bool expected) + { + _ = MathUtils.IsPow2(testNumber).Should().Be(expected); + } + + [Theory] + [InlineData(-2, -1)] + [InlineData(-1, -1)] + [InlineData(0, -1)] + [InlineData(1, 0)] + [InlineData(2, 1)] + [InlineData(3, -1)] + [InlineData(4, 2)] + [InlineData(8, 3)] + public void GetPow2Shift(long testNumber, int expected) + { + _ = MathUtils.GetPow2Shift(testNumber).Should().Be(expected); + } } }