diff --git a/src/Managed.UnitTests/NumberTheoryTests/IntegerTheoryTest.cs b/src/Managed.UnitTests/NumberTheoryTests/IntegerTheoryTest.cs index 8741ee6e..8f8db543 100644 --- a/src/Managed.UnitTests/NumberTheoryTests/IntegerTheoryTest.cs +++ b/src/Managed.UnitTests/NumberTheoryTests/IntegerTheoryTest.cs @@ -131,6 +131,106 @@ namespace MathNet.Numerics.UnitTests.NumberTheoryTests Assert.IsFalse(IntegerTheory.IsPowerOfTwo(Int64.MaxValue-1), "Int32.MaxValue-1 (-)"); } + [Test] + public void CeilingToPowerOfHandlesPositiveIntegersCorrectly32() + { + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(0), "0"); + Assert.AreEqual(1, IntegerTheory.CeilingToPowerOfTwo(1), "1"); + Assert.AreEqual(2, IntegerTheory.CeilingToPowerOfTwo(2), "2"); + Assert.AreEqual(4, IntegerTheory.CeilingToPowerOfTwo(3), "3"); + Assert.AreEqual(4, IntegerTheory.CeilingToPowerOfTwo(4), "4"); + + for (int i = 2; i < 31; i++) + { + int x = 1 << i; + Assert.AreEqual(x, IntegerTheory.CeilingToPowerOfTwo(x), x.ToString()); + Assert.AreEqual(x, IntegerTheory.CeilingToPowerOfTwo(x - 1), x + "-1"); + Assert.AreEqual(x, IntegerTheory.CeilingToPowerOfTwo((x >> 1) + 1), x + "/2+1"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(-x), "-" + x); + } + + const int maxPowerOfTwo = 0x40000000; + Assert.AreEqual(maxPowerOfTwo, IntegerTheory.CeilingToPowerOfTwo(maxPowerOfTwo), "max"); + Assert.AreEqual(maxPowerOfTwo, IntegerTheory.CeilingToPowerOfTwo(maxPowerOfTwo - 1), "max"); + } + + [Test] + public void CeilingToPowerOfHandlesPositiveIntegersCorrectly64() + { + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo((long)0), "0"); + Assert.AreEqual(1, IntegerTheory.CeilingToPowerOfTwo((long)1), "1"); + Assert.AreEqual(2, IntegerTheory.CeilingToPowerOfTwo((long)2), "2"); + Assert.AreEqual(4, IntegerTheory.CeilingToPowerOfTwo((long)3), "3"); + Assert.AreEqual(4, IntegerTheory.CeilingToPowerOfTwo((long)4), "4"); + + for (int i = 2; i < 63; i++) + { + long x = ((long)1) << i; + Assert.AreEqual(x, IntegerTheory.CeilingToPowerOfTwo(x), x.ToString()); + Assert.AreEqual(x, IntegerTheory.CeilingToPowerOfTwo(x - 1), x + "-1"); + Assert.AreEqual(x, IntegerTheory.CeilingToPowerOfTwo((x >> 1) + 1), x + "/2+1"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(-x), "-" + x); + } + + const long maxPowerOfTwo = 0x4000000000000000; + Assert.AreEqual(maxPowerOfTwo, IntegerTheory.CeilingToPowerOfTwo(maxPowerOfTwo), "max"); + Assert.AreEqual(maxPowerOfTwo, IntegerTheory.CeilingToPowerOfTwo(maxPowerOfTwo - 1), "max"); + } + + [Test] + public void CeilingToPowerOfTwoReturnsZeroForNegativeNumbers32() + { + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(-1), "-1"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(-2), "-2"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(-3), "-3"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(-4), "-4"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(Int32.MinValue), "Int32.MinValue"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(Int32.MinValue + 1), "Int32.MinValue+1"); + } + + [Test] + public void CeilingToPowerOfTwoReturnsZeroForNegativeNumbers64() + { + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo((long)-1), "-1"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo((long)-2), "-2"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo((long)-3), "-3"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo((long)-4), "-4"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(Int64.MinValue), "Int64.MinValue"); + Assert.AreEqual(0, IntegerTheory.CeilingToPowerOfTwo(Int64.MinValue + 1), "Int64.MinValue+1"); + } + + [Test] + public void CeilingToPowerOfTwoThrowsWhenResultWouldOverflow32() + { + Assert.Throws( + typeof (ArgumentOutOfRangeException), + () => IntegerTheory.CeilingToPowerOfTwo(Int32.MaxValue)); + + const int maxPowerOfTwo = 0x40000000; + Assert.Throws( + typeof(ArgumentOutOfRangeException), + () => IntegerTheory.CeilingToPowerOfTwo(maxPowerOfTwo + 1)); + + Assert.DoesNotThrow( + () => IntegerTheory.CeilingToPowerOfTwo(maxPowerOfTwo - 1)); + } + + [Test] + public void CeilingToPowerOfTwoThrowsWhenResultWouldOverflow64() + { + Assert.Throws( + typeof(ArgumentOutOfRangeException), + () => IntegerTheory.CeilingToPowerOfTwo(Int64.MaxValue)); + + const long maxPowerOfTwo = 0x4000000000000000; + Assert.Throws( + typeof(ArgumentOutOfRangeException), + () => IntegerTheory.CeilingToPowerOfTwo(maxPowerOfTwo + 1)); + + Assert.DoesNotThrow( + () => IntegerTheory.CeilingToPowerOfTwo(maxPowerOfTwo - 1)); + } + [Test] public void TestIsPerfectSquare32() { diff --git a/src/Managed/NumberTheory/IntegerTheory.cs b/src/Managed/NumberTheory/IntegerTheory.cs index 3130d667..dfe0bf8a 100644 --- a/src/Managed/NumberTheory/IntegerTheory.cs +++ b/src/Managed/NumberTheory/IntegerTheory.cs @@ -95,6 +95,65 @@ namespace MathNet.Numerics.NumberTheory return number > 0 && (number & (number - 1)) == 0x0; } + /// + /// Find the closest perfect power of two that is larger or equal to the provided + /// 32 bit integer. + /// + /// The number of which to find the closest upper power of two. + /// A power of two. + /// + public static int CeilingToPowerOfTwo(this int number) + { + if(number == Int32.MinValue) + { + return 0; + } + + const int maxPowerOfTwo = 0x40000000; + if(number > maxPowerOfTwo) + { + throw new ArgumentOutOfRangeException("number"); + } + + number--; + number |= number >> 1; + number |= number >> 2; + number |= number >> 4; + number |= number >> 8; + number |= number >> 16; + return number + 1; + } + + /// + /// Find the closest perfect power of two that is larger or equal to the provided + /// 64 bit integer. + /// + /// The number of which to find the closest upper power of two. + /// A power of two. + /// + public static long CeilingToPowerOfTwo(this long number) + { + if (number == Int64.MinValue) + { + return 0; + } + + const long maxPowerOfTwo = 0x4000000000000000; + if (number > maxPowerOfTwo) + { + throw new ArgumentOutOfRangeException("number"); + } + + number--; + number |= number >> 1; + number |= number >> 2; + number |= number >> 4; + number |= number >> 8; + number |= number >> 16; + number |= number >> 32; + return number + 1; + } + /// /// Find out whether the provided 32 bit integer is a perfect square, i.e. a square of an integer. ///