【问题标题】:Pack and unpack multiple integers into and from an Uint64在 Uint64 中打包和解包多个整数
【发布时间】:2026-02-03 03:30:01
【问题描述】:

需要将以下内容打包解包成 UInt64
UInt25
UInt5
UInt7
UInt27

具有以下用于从 UInt32 打包和解包 UInt27 和 UInt5
但我无法通过 2
我的背景是数学(不是计算机科学)

UInt32 highlow;
UInt32 high;
byte  low;
int two27 = (Int32)Math.Pow(2, 27);
for (UInt32 i = 0; i < two27; i++)
{
    highlow = ((UInt32)i) << 5;
    high = highlow >> 5;
    if (high != i)
    {
        Debug.WriteLine("high wrong A " + high.ToString() + " " + i.ToString());
    }
    for (byte j = 0; j < 32; j++)
    {
        highlow = (((UInt32)i) << 5) | j;
        high = highlow >> 5;
        if (high != i)
        {
            Debug.WriteLine("high wrong B " + high.ToString() + " " + i.ToString());
        }
        low = (byte)(highlow & 0x1f);
        if (low != j)
        {
            Debug.WriteLine("low wrong " + low.ToString() + " " + j.ToString());
        }
    }               
}

基于接受答案的代码(未测试 i27 循环达到 2 的完整循环)

UInt32 bits27;
UInt32 bits25;
UInt32 bits7;
UInt32 bits5;
UInt32 int27 = (UInt32)Math.Pow(2,27);
UInt32 int25 = (UInt32)Math.Pow(2,25);
UInt32 int7  = (UInt32)Math.Pow(2,7);
UInt32 int5  = (UInt32)Math.Pow(2,5);
UInt64 packed;
//ulong packed = (bits27) | ((ulong)bits25 << 27) | ((ulong)bits7 << 52) | ((ulong)bits5 << 59);
for             (UInt32 i27 = 0; i27 < int27; i27++)
{
    for         (UInt32 i25 = 0; i25 < int25; i25++)
    {
        for     (UInt32  i7 = 0;  i7 <  int7; i7++)
        {
            for (UInt32  i5 = 0;  i5 <  int5; i5++)
            {
                packed = (UInt64)(i27) | ((UInt64)i25 << 27) | ((UInt64)i7 << 52) | ((UInt64)i5 << 59);

                bits27 = (UInt32)(packed & ((1 << 27) - 1));
                bits25 = (UInt32)((packed >> 27) & ((1 << 25) - 1));
                bits7 =  (UInt32)((packed >> 52) & ((1 << 7) - 1));
                bits5 =  (UInt32)((packed >> 59) & ((1 << 5) - 1));
                if (bits27 != i27) Debug.WriteLine("bits27 != i27");
                if (bits25 != i25) Debug.WriteLine("bits25 != i25");
                if (bits7  != i7)  Debug.WriteLine("bits7  !=  i7");
                if (bits5  != i5)  Debug.WriteLine("bits5  !=  i5");
            }
        }
    }
}

【问题讨论】:

  • 您可能会考虑使用布尔数组和 uint64 的 union - 或使用 long int(您的机器上是 64 位),然后进行移位和添加...跨度>
  • 你正在循环 i,一个 `uint16',到 2^27。不是你唯一的问题,但不会工作......如果结果溢出,结果是未定义的,所以使用可以保存结果的类型!
  • @Floris 同意我应该是 Unint32。那是测试的问题。那打包和解包不起作用怎么办?
  • 您需要 64 位,而不是 32 位,才能使事情适应。当您将内容转换为 UInt32 时,您会丢弃前 32 位。当前接受的答案并不能保证这一点。如果您的编译器定义了 uint64 类型(或等效类型),那就更好了。如果没有,请自行添加 #define uint64 (unsigned long long)
  • 从你所说的我得出的结论是,在你的平台/编译器上,ulong 是 UInt64。这意味着接受的答案(它很干净,实际上非常接近我在原始评论中提出的建议)对您来说非常有效 - 您接受它是正确的。但我希望看到@BenVoigt 改进答案以明确指出ulong === UInt64,因为标准不保证这一点。

标签: c# .net int


【解决方案1】:

移位运算符是正确的解决方案,但请注意,它们不会自动使结果比输入更宽 - 您需要转换输入。

包装:

ulong packed = (bits27) | ((ulong)bits25 << 27) | ((ulong)bits7 << 52) | ((ulong)bits5 << 59);

解压:

bits27 = (uint) (packed        & ((1 << 27) - 1));
bits25 = (uint)((packed >> 27) & ((1 << 25) - 1));
bits7  = (uint)((packed >> 52) & ((1 <<  7) - 1));
bits5  = (uint)((packed >> 59) & ((1 <<  5) - 1));

【讨论】:

  • 我会测试的。如果这行得通,那就太酷了。不知道你说的强制转换输入是什么意思?
  • (ulong) bits25 是演员
  • 这适用于 unsigned long 为 64 位长的平台。该标准保证long 是32 位。你需要unsigned long long(在C99中指定)来保证64位。
  • 这不是问题的一部分。但是当我把它带到 32 时,它打破了,因为 shift 假设签署了 Int32。 UInt64 u1 = (UInt64)1; ((u1
  • @Blam:是的,我肯定会在转换需要使用多于低 32 位的情况下使用 cast-to-ulong。
【解决方案2】:

似乎将数字转换为二进制、填充或截断到正确的长度、连接它们然后从二进制构造您的 64 位类型会容易得多。

var packedInt64 = Convert.ToInt64(Convert.ToString(ui25, 2).PadLeft(25, '0') +
                                  Convert.ToString(ui5, 2).PadLeft(5, '0') +
                                  Convert.ToString(ui7, 2).PadLeft(7, '0') +
                                  Convert.ToString(ui27, 2).PadLeft(2, '0'), 2);

解压:

var binary = Convert.ToString(packedInt64, 2);
ui25 = Convert.ToUInt32(binary.Substring(0, 24));
ui5 = Convert.ToUInt32(binary.Substring(24, 5));
etc.

【讨论】:

  • 这不仅比移位效率低,而且代码也更难阅读。
  • @BenVoigt 它的效率肯定要低得多,但我认为它更容易阅读。查看上面的代码示例,如果您还不知道它在做什么,需要很长时间才能弄清楚它在做什么。调试它还需要一个 SO 问题,在这里调试此代码相当容易。
  • @BenVoigt 我还没有加载你的答案——我同意你的代码比我的要好得多。我希望转换为更像布尔数组而不是使用字符串的东西 - 这是我可以使这种方法看起来最好的。
  • @Blam 我已经添加了一个解压代码的示例,但是如果你理解 Ben 的代码,我可能会使用它并附上解释性注释。
  • 你说得对,乍一看可能不太清楚 Ben 的代码在做什么。但这很容易使用注释或方法名称来解决。一旦你知道目标是什么,代码就很明显了。