将UInt64中的设置位移动到各自字节的右侧

时间:2016-09-08 17:26:32

标签: 64-bit bit-manipulation bitwise-operators

我有一个UInt64值,有些位打开,有些打开,例如:

01010101 01010101 01010101 01010101 01010101 01010101 01010101 01010101

如何轻松地将设置位向右移动,例如它们位于各自字节的右端,例如:

00001111 00001111 00001111 00001111 00001111 00001111 00001111 00001111

我已经看过将这些位一直移动到64位无符号整数右边的问题,但我只想把它们移到它们所在的字节的右边。如果可能的话。 p>

感谢。

1 个答案:

答案 0 :(得分:0)

using System;
using System.Linq;

namespace ConsoleApplication5
{
  public class Program
  {
    public static void Main(String[] args)
    {
      var inputAsBinaryString = "01010101 01010101 01010101 01010101 01010101 01010101 01010101 01010101";
      var inputAsUInt64 = GetBinaryStringAsUInt64(inputAsBinaryString);

      var actualAsUInt64 = GetRightAlignedBytes(inputAsUInt64);
      var actualAsBinaryString = GetAsBinaryString(actualAsUInt64);

      var expectedAsBinaryString = "00001111 00001111 00001111 00001111 00001111 00001111 00001111 00001111";
      var expectedAsUInt64 = GetBinaryStringAsUInt64(expectedAsBinaryString);
    } // <-- Set a breakpoint here and inspect the values.

    /* Bit-manipulation methods. */

    private static UInt64 GetRightAlignedBytes(UInt64 n)
    {
      var rightAlignedByteArray =
        BitConverter
        .GetBytes(n)
        .Select(b => GetRightAlignedByte(b))
        .ToArray();
      return BitConverter.ToUInt64(rightAlignedByteArray, 0);
    }

    /* Shove all of a byte's bits to the right. */
    private static Byte GetRightAlignedByte(Byte b)
    {
      /* The << operator only works on 32 and 64 bit values.
         This requires treating the result as an Int32 until it's returned. */
      Int32 result = 0;
      var numberOfSetBits = GetNumberOfSetBits(b);

      for (Byte n = 1; n <= numberOfSetBits; n++)
      {
        /* Need to set n bits, but only perform n - 1 left shifts. */

        result |= 1;

        if (n < numberOfSetBits)
          result = result << 1;
      }

      return (Byte) result;
    }

    private static Byte GetNumberOfSetBits(Byte b)
    {
      /* There are many ways to count the number of "set" bits in a byte.

         This StackOverflow question

           http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer

         has a mind-numbing collection of answers.
         Most of them are probably more efficient than this method. */

      Int32 result = 0;

      /* The >> operator only works on 32 and 64 bit values.
         This requires converting the Byte parameter "b" to an Int32. */
      Int32 n = b;

      while (n > 0)
      {
        result += (n & 1);
        n = n >> 1;
      }

      return (Byte) result;
    }

    /* GetBinaryStringAs* methods */

    private static Int32 GetBinaryStringAsInt32(String s)
    {
      return Convert.ToInt32(String.Join("", s.Trim().Where(c => (c == '0') || (c == '1'))), 2);
    }

    private static UInt64 GetBinaryStringAsUInt64(String s)
    {
      return Convert.ToUInt64(String.Join("", s.Trim().Where(c => (c == '0') || (c == '1'))), 2);
    }

    /* GetAsBinaryString methods. */

    private static String GetAsBinaryString_Helper(Byte[] bytes)
    {
      /* The order of the bytes returned by System.BitConverter.GetBytes()
         depends on the CPU architecture.  The returned byte array
         will round-trip with other BitConverter methods, like its
         ToInt32() method.  But those same bytes will not round-trip
         with any of the System.Convert methods, like ToInt32(String, Int32).

         The System.Convert.To* methods expect the order of the bytes they
         receive to be the *reverse* of the order returned by
         System.BitConverter.GetBytes().

         The value returned by this method can - after stripping off the spaces -
         be fed into a System.Convert.To*() method.

         For example, this round-trip test should print "True":

                         // Hi byte                    Lo byte
          Int32 n = 257; // 00000000 00000000 00000001 00000001
          Console.WriteLine(GetBinaryStringAsInt32(GetAsBinaryString(n)) == n);

       */

      return String.Join(" ", bytes.Reverse().Select(b => GetAsBinaryString(b)));
    }

    private static String GetAsBinaryString(Int32 n)
    {
      /* Note that signed integers use two's complement
         binary representation for negative numbers.

         For example, calling this method with a parameter
         of -42 returns this string:

          11111111 11111111 11111111 11010110

       */
      return GetAsBinaryString_Helper(BitConverter.GetBytes(n));
    }

    private static String GetAsBinaryString(UInt64 n)
    {
      return GetAsBinaryString_Helper(BitConverter.GetBytes(n));
    }

    private static String GetAsBinaryString(Byte n)
    {
      return Convert.ToString(n, 2).PadLeft(8, '0');
    }
  }
}