delete from hateblo.jp where 1=1;

タイトルに意味はありません。

C# でもビットスワップしたい

対象

以下のマニアックな人向けの記事です。

  • C#
  • LSB と MSB を入れ替えたい

ファーム焼きをしている界隈の人に刺さるかもしれません。 むしろモトローラコードのエンディアンを変換するプログラムを提供しなさいとも言われるかもしれませんが。

方法

ビット演算で入れ替える

using System;

namespace BitReverse
{
    /// <summary>
    /// Swap MSB and LSB
    /// </summary>
    public static class BitReverse
    {

        /// <summary>
        /// Swap MSB and LSB
        /// </summary>
        /// <param name="input">input number</param>
        /// <returns>Swapped input number</returns>
        public static ulong UInt64(ulong input)
        {
            return ReverseBit(input, 64);
        }
        /// <summary>
        /// Swap MSB and LSB
        /// </summary>
        /// <param name="input">input number</param>
        /// <returns>Swapped input number</returns>
        public static uint UInt32(uint input)
        {
            return (uint)ReverseBit(input, 32);
        }
        /// <summary>
        /// Swap MSB and LSB
        /// </summary>
        /// <param name="input">input number</param>
        /// <returns>Swapped input number</returns>
        public static ushort UInt16(ushort input)
        {
            return (ushort)ReverseBit(input, 16);
        }
        /// <summary>
        /// Swap MSB and LSB
        /// </summary>
        /// <param name="input">input number</param>
        /// <returns>Swapped input number</returns>
        public static byte UInt8(byte input)
        {
            return (byte)ReverseBit(input, 8);
        }

        /// <summary>
        /// Swap MSB and LSB
        /// </summary>
        /// <param name="input">input number</param>
        /// <param name="bit">size of bits</param>
        /// <returns>Swapped input number</returns>
        /// <remarks>
        /// Original code is from https://ja.stackoverflow.com/a/9239/882
        /// </remarks>
        private static ulong ReverseBit(ulong input, int bit)
        {
            ulong swap = input;
            switch (bit)
            {
                case 64:
                    swap = ((swap & 0x00000000ffffffff) << 32) | ((swap >> 32) & 0x00000000ffffffff);
                    goto case 32;
                case 32:
                    swap = ((swap & 0x0000ffff0000ffff) << 16) | ((swap >> 16) & 0x0000ffff0000ffff);
                    goto case 16;
                case 16:
                    swap = ((swap & 0x00ff00ff00ff00ff) << 8) | ((swap >> 8) & 0x00ff00ff00ff00ff);
                    goto case 8;
                case 8:
                    swap = ((swap & 0x0f0f0f0f0f0f0f0f) << 4) | ((swap >> 4) & 0x0f0f0f0f0f0f0f0f);
                    goto case 4;
                case 4:
                    swap = ((swap & 0x3333333333333333) << 2) | ((swap >> 2) & 0x3333333333333333);
                    goto case 2;
                case 2:
                    swap = ((swap & 0x5555555555555555) << 1) | ((swap >> 1) & 0x5555555555555555);
                    break;
                default:
                    throw new ArgumentException("bit is out of range: 2/4/8/16/32/64", nameof(bit));
            }
            return swap;
        }
    }
}

C# だと fail through が出来ないので、 goto を使っています。安全ですね。

参考文献

ja.stackoverflow.com

ループしてビットを入れ替える

using System;

namespace BitReverse
{
    /// <summary>
    /// Swap MSB and LSB
    /// </summary>
    public static class BitReverseLoop
    {

        /// <summary>
        /// Swap MSB and LSB
        /// </summary>
        /// <param name="input">input number</param>
        /// <returns>Swapped input number</returns>
        public static ulong UInt64(ulong input)
        {
            return ReverseBit(input, 64);
        }
        /// <summary>
        /// Swap MSB and LSB
        /// </summary>
        /// <param name="input">input number</param>
        /// <returns>Swapped input number</returns>
        public static uint UInt32(uint input)
        {
            return (uint)ReverseBit(input, 32);
        }
        /// <summary>
        /// Swap MSB and LSB
        /// </summary>
        /// <param name="input">input number</param>
        /// <returns>Swapped input number</returns>
        public static ushort UInt16(ushort input)
        {
            return (ushort)ReverseBit(input, 16);
        }
        /// <summary>
        /// Swap MSB and LSB
        /// </summary>
        /// <param name="input">input number</param>
        /// <returns>Swapped input number</returns>
        public static byte UInt8(byte input)
        {
            return (byte)ReverseBit(input, 8);
        }

        /// <summary>
        /// Swap MSB and LSB
        /// </summary>
        /// <param name="input">input number</param>
        /// <param name="bit">size of bits</param>
        /// <returns>Swapped input number</returns>
        /// <remarks>
        /// Original code is from https://ja.stackoverflow.com/a/7500/882
        /// </remarks>
        private static ulong ReverseBit(ulong input, int bit)
        {
            ulong swap = 0;
            while(bit-- > 0)
            {
                swap <<= 1;
                swap |= (input & 1u);
                input >>= 1;
            }
            return swap;
        }
    }
}

1Lu とかにしないといけないように見えるけど、暗黙的型変換されるので 1u で良いです。

参考文献

ja.stackoverflow.com

ライセンス

stackoverflow のライセンスに基づきます。CC BY-SA 3.0。 私が記載したものは WTFPL Version 2.0 とします。

その他

テストコード等は gist を参照ください。

BitReverse · GitHub