//******************************************************************************************************
// BitMath.cs - Gbtc
//
// Copyright © 2014, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 06/08/2012 - Steven E. Chisholm
// Generated original version of source code.
//
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
namespace GSF
{
///
/// Contains some random and useful functions.
///
public static class BitMath
{
#region [ Is Power Of Two ]
///
/// Determines if the number is a power of 2.
///
/// The value to check power of two properties
///
/// If is less than zero
public static bool IsPowerOfTwo(int value)
{
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value), "Must be greater than or equal to zero");
return IsPowerOfTwo((uint)value);
}
///
/// Determines if the number is a power of 2.
///
/// The value to check power of two properties
/// If is less than zero
public static bool IsPowerOfTwo(long value)
{
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value), "Must be greater than or equal to zero");
return IsPowerOfTwo((ulong)value);
}
///
/// Determines if the number is a power of 2.
///
/// The value to check power of two properties
///
public static bool IsPowerOfTwo(uint value)
{
return value != 0 && ((value & (value - 1)) == 0);
}
///
/// Determines if the number is a power of 2.
///
/// The value to check power of two properties
///
public static bool IsPowerOfTwo(ulong value)
{
return value != 0 && ((value & (value - 1)) == 0);
}
#endregion
#region [ Count Bits ]
///
/// Counts the number of bits that are set
///
///
///
public static int CountBitsSet(uint value)
{
uint count;
for (count = 0; value > 0; value >>= 1)
{
count += value & 1;
}
return (int)count;
}
///
/// Counts the number of bits that are set
///
///
///
public static int CountBitsSet(ulong value)
{
ulong count;
for (count = 0; value > 0; value >>= 1)
{
count += value & 1;
}
return (int)count;
}
///
/// Counts the number of bits that are not set
///
///
///
public static int CountBitsCleared(uint value)
{
return CountBitsSet(~value);
}
///
/// Counts the number of bits that are not set
///
///
///
public static int CountBitsCleared(ulong value)
{
return CountBitsSet(~value);
}
#endregion
#region [ Round To Power Of Two ]
///
/// Rounds a number up to the nearest power of 2.
/// If the value is a power of two, the same value is returned.
/// If the value is larger than the largest power of 2. It is rounded down.
///
///
///
///
/// Method based on a method found at: http://graphics.stanford.edu/~seander/bithacks.htm
/// Subtitle: Round up to the next highest power of 2
///
public static ulong RoundUpToNearestPowerOfTwo(ulong value)
{
if (value == 0)
return 1;
if (value > (1ul << 62))
return 1ul << 63;
value--;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value |= value >> 32;
value++;
return value;
}
///
/// Rounds a number up to the nearest power of 2.
/// If the value is a power of two, the same value is returned.
/// If the value is larger than the largest power of 2. It is rounded down.
///
///
///
///
/// Method based on a method found at: http://graphics.stanford.edu/~seander/bithacks.htm
/// Subtitle: Round up to the next highest power of 2
///
public static uint RoundUpToNearestPowerOfTwo(uint value)
{
if (value == 0)
return 1;
if (value > (1u << 30))
return 1u << 31;
value--;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value++;
return value;
}
///
/// Rounds a number down to the nearest power of 2.
/// If the value is a power of two, the same value is returned.
/// If value is zero, one is returned.
///
///
///
public static ulong RoundDownToNearestPowerOfTwo(ulong value)
{
if (value == 0ul)
return 1;
return (1ul << 63) >> CountLeadingZeros(value);
}
///
/// Rounds a number down to the nearest power of 2.
/// If the value is a power of two, the same value is returned.
/// If value is zero, 1 is returned.
///
///
///
public static uint RoundDownToNearestPowerOfTwo(uint value)
{
if (value == 0u)
return 1;
return (1u << 31) >> CountLeadingZeros(value);
}
#endregion
///
/// Creates a bit mask for a number with the given number of bits.
///
///
///
public static ulong CreateBitMask(int bitCount)
{
if (bitCount == 0)
return 0;
return ulong.MaxValue >> (64 - bitCount);
}
#region [ Count Leading/Trailing Zeros ]
///
/// Counts the number of consecutive 0's starting from the lowest bit working up.
///
///
/// Unfortunately, c# cannot call the cpu instruction ctz
/// Example from http://en.wikipedia.org/wiki/Find_first_set
///
public static int CountTrailingZeros(uint value)
{
if (value == 0)
return 32;
int position = 0;
if ((value & 0xffffu) == 0u)
{
value >>= 16;
position += 16;
}
if ((value & 0xffu) == 0u)
{
value >>= 8;
position += 8;
}
if ((value & 0xfu) == 0u)
{
value >>= 4;
position += 4;
}
if ((value & 0x3u) == 0u)
{
value >>= 2;
position += 2;
}
if ((value & 0x1u) == 0u)
{
position += 1;
}
return position;
}
///
/// Counts the number of consecutive 0's starting from the lowest bit working up.
///
///
/// Unfortunately, c# cannot call the cpu instruction ctz
/// Example from http://en.wikipedia.org/wiki/Find_first_set
///
public static int CountTrailingZeros(ulong value)
{
if (value == 0)
return 64;
int position = 0;
if ((value & 0xfffffffful) == 0ul)
{
value >>= 32;
position += 32;
}
if ((value & 0xfffful) == 0ul)
{
value >>= 16;
position += 16;
}
if ((value & 0xfful) == 0ul)
{
value >>= 8;
position += 8;
}
if ((value & 0xful) == 0ul)
{
value >>= 4;
position += 4;
}
if ((value & 0x3ul) == 0ul)
{
value >>= 2;
position += 2;
}
if ((value & 0x1ul) == 0ul)
{
position += 1;
}
return position;
}
///
/// Counts the number of consecutive 0's starting from the highest bit working down.
///
///
///
///
/// Unfortunately, c# cannot call the cpu instruction clz
/// Example from http://en.wikipedia.org/wiki/Find_first_set
///
public static int CountLeadingZeros(uint value)
{
if (value == 0ul)
return 32;
int position = 0;
if ((value & 0xFFFF0000u) == 0u)
{
value <<= 16;
position += 16;
}
if ((value & 0xFF000000u) == 0u)
{
value <<= 8;
position += 8;
}
if ((value & 0xF0000000) == 0u)
{
value <<= 4;
position += 4;
}
if ((value & 0xC0000000) == 0u)
{
value <<= 2;
position += 2;
}
if ((value & 0x80000000) == 0u)
{
position += 1;
}
return position;
}
///
/// Counts the number of consecutive 0's starting from the highest bit working down.
///
///
/// Unfortunately, c# cannot call the cpu instruction clz
/// Example from http://en.wikipedia.org/wiki/Find_first_set
///
public static int CountLeadingZeros(ulong value)
{
if (value == 0ul)
return 64;
int position = 0;
if ((value & 0xFFFFFFFF00000000ul) == 0ul)
{
value <<= 32;
position += 32;
}
if ((value & 0xFFFF000000000000ul) == 0ul)
{
value <<= 16;
position += 16;
}
if ((value & 0xFF00000000000000ul) == 0ul)
{
value <<= 8;
position += 8;
}
if ((value & 0xF000000000000000ul) == 0ul)
{
value <<= 4;
position += 4;
}
if ((value & 0xC000000000000000ul) == 0ul)
{
value <<= 2;
position += 2;
}
if ((value & 0x8000000000000000ul) == 0ul)
{
position += 1;
}
return position;
}
#endregion
#region [ Count Leading/Trailing Ones ]
///
/// Counts the number of consecutive 1's starting from the lowest bit working up.
///
public static int CountTrailingOnes(uint value)
{
return CountTrailingZeros(~value);
}
///
/// Counts the number of consecutive 1's starting from the lowest bit working up.
///
public static int CountTrailingOnes(ulong value)
{
return CountTrailingZeros(~value);
}
///
/// Counts the number of consecutive 1's starting from the highest bit working down.
///
public static int CountLeadingOnes(uint value)
{
return CountLeadingZeros(~value);
}
///
/// Counts the number of consecutive 1's starting from the highest bit working down.
///
public static int CountLeadingOnes(ulong value)
{
return CountLeadingZeros(~value);
}
#endregion
///
/// Returns the bit position for every bit that is set in the provided value.
/// Bit positions are defined as 0-63;
///
///
///
public static IEnumerable GetSetBitPositions(ulong value)
{
// Once value becomes zero, the remainder of the loop can be short-cut
for (int x = 0; value != 0; x++, value >>= 1)
{
if ((value & 1) == 1)
yield return x;
}
}
///
/// Returns the bit position for every bit that is set in the provided value.
/// Bit positions are defined as 0-31;
///
///
///
public static IEnumerable GetSetBitPositions(uint value)
{
// Once value becomes zero, the remainder of the loop can be short-cut
for (int x = 0; value != 0; x++, value >>= 1)
{
if ((value & 1) == 1)
yield return x;
}
}
///
/// Returns the bit position for every bit that is cleared in the provided value.
/// Bit positions are defined as 0-31;
///
///
///
public static IEnumerable GetClearedBitPositions(uint value)
{
return GetSetBitPositions(~value);
}
///
/// Returns the bit position for every bit that is cleared in the provided value.
/// Bit positions are defined as 0-63;
///
///
///
public static IEnumerable GetClearedBitPositions(ulong value)
{
return GetSetBitPositions(~value);
}
}
}