diff --git a/src/Numerics/Euclid.cs b/src/Numerics/Euclid.cs index 808505c2..394884e5 100644 --- a/src/Numerics/Euclid.cs +++ b/src/Numerics/Euclid.cs @@ -271,6 +271,27 @@ namespace MathNet.Numerics return ((long)1) << (int)exponent; } + /// + /// Evaluate the binary logarithm of an integer number. + /// + /// Two-step method using a De Bruijn-like sequence table lookup. + public static int Log2(this int number) + { + number |= number >> 1; + number |= number >> 2; + number |= number >> 4; + number |= number >> 8; + number |= number >> 16; + + return MultiplyDeBruijnBitPosition[(uint)(number * 0x07C4ACDDU) >> 27]; + } + + static readonly int[] MultiplyDeBruijnBitPosition = new int[32] + { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 + }; + /// /// Find the closest perfect power of two that is larger or equal to the provided /// 32 bit integer. diff --git a/src/UnitTests/EuclidTests/IntegerTheoryTest.cs b/src/UnitTests/EuclidTests/IntegerTheoryTest.cs index 7df6eeaf..9d8db87d 100644 --- a/src/UnitTests/EuclidTests/IntegerTheoryTest.cs +++ b/src/UnitTests/EuclidTests/IntegerTheoryTest.cs @@ -442,6 +442,24 @@ namespace MathNet.Numerics.UnitTests.EuclidTests () => ((long)0).PowerOfTwo()); } + /// + /// Log2 matches floating point for int32. + /// + [Test] + public void Log2MatchesFloatingPoint32() + { + for (var i = 0; i < 31; i++) + { + int number = i.PowerOfTwo(); + Assert.AreEqual((int)Math.Log(number, 2), number.Log2()); + Assert.AreEqual((int)Math.Log(number + 1, 2), (number + 1).Log2()); + if (number > 1) + { + Assert.AreEqual((int)Math.Log(number - 1, 2), (number - 1).Log2()); + } + } + } + /// /// Test if int32 is perfect square. ///