C#中多值编码为64位long的位操作实现咨询
long in C# Hey there! Let's walk through how to pack your date/time values (and extra data) into a single long—bitwise operations might seem intimidating at first, but they're straightforward once you grasp the basics of shifting and masking.
First, Let's Lock in the Bit Layout
You specified a total of 63 bits to use (we'll leave the 64th bit empty to avoid signed integer headaches). Here's the fixed structure we'll implement:
- Year: 12 bits (covers 0–4095, easily handles your max of 2048) → occupies bits 51–62 (counting from 0 as the lowest bit)
- Month: 6 bits (0–63, fits your max of 16) → occupies bits 45–50
- Day: 7 bits (0–127, handles your max of 32) → occupies bits 38–44
- Hour: 7 bits (0–127, fits your max of 32) → occupies bits 31–37
- Extra Data: 31 bits (for any additional values you might need later) → occupies bits 0–30
Core Bitwise Concepts to Know
We'll use three simple operations to make this work:
- Left Shift (
<<): Moves a number's bits to the left by a set number of positions, padding with zeros. This lets us "slot" each value into its designated spot in thelong. - Bitwise OR (
|): Merges numbers by setting a bit to 1 if it's 1 in either value. We use this to combine all shifted values into onelong. - Bitwise AND (
&): Extracts specific bits by masking out the rest. This is how we pull individual values back out during decoding.
Encoding Function
This function takes your values, validates they fit their bit ranges, and packs them into a single long:
public static long EncodeFields(int year, int month, int day, int hour, long extraData = 0) { // Validate inputs to prevent overflow into other fields if (year is < 0 or > 4095) throw new ArgumentOutOfRangeException(nameof(year), "Year must be between 0 and 4095"); if (month is < 0 or > 63) throw new ArgumentOutOfRangeException(nameof(month), "Month must be between 0 and 63"); if (day is < 0 or > 127) throw new ArgumentOutOfRangeException(nameof(day), "Day must be between 0 and 127"); if (hour is < 0 or > 127) throw new ArgumentOutOfRangeException(nameof(hour), "Hour must be between 0 and 127"); if ((extraData & ~0x7FFFFFFFL) != 0) throw new ArgumentOutOfRangeException(nameof(extraData), "Extra data must fit in 31 bits"); long encodedValue = 0; // Shift each value to its position and merge with OR encodedValue |= (long)year << 51; encodedValue |= (long)month << 45; encodedValue |= (long)day << 38; encodedValue |= (long)hour << 31; encodedValue |= extraData & 0x7FFFFFFFL; // Keep only the first 31 bits of extra data return encodedValue; }
Decoding Function
This function takes the encoded long and extracts each original value using masking and shifting:
public static void DecodeFields(long encodedValue, out int year, out int month, out int day, out int hour, out long extraData) { // Mask and shift to pull out each field year = (int)((encodedValue >> 51) & 0xFFFL); // 0xFFF = 12 bits of 1s month = (int)((encodedValue >> 45) & 0x3FL); // 0x3F = 6 bits of 1s day = (int)((encodedValue >> 38) & 0x7FL); // 0x7F = 7 bits of 1s hour = (int)((encodedValue >> 31) & 0x7FL); // Same mask as day extraData = encodedValue & 0x7FFFFFFFL; // Extract the first 31 bits }
Test It Out!
Here's a quick example to see how it works in practice:
// Sample input values int testYear = 2023; int testMonth = 10; int testDay = 25; int testHour = 14; long testExtraData = 123456; // Encode the values long encoded = EncodeFields(testYear, testMonth, testDay, testHour, testExtraData); Console.WriteLine($"Encoded value: {encoded}"); // Decode them back DecodeFields(encoded, out int decodedYear, out int decodedMonth, out int decodedDay, out int decodedHour, out long decodedExtra); Console.WriteLine($"Decoded Values: Year={decodedYear}, Month={decodedMonth}, Day={decodedDay}, Hour={decodedHour}, Extra={decodedExtra}");
Key Notes
- We left the 64th bit unused because
longis a signed integer—using this bit could create negative values that break decoding. - The validation checks are critical to stop one field from spilling into another (e.g., a year larger than 4095 would overwrite the month bits).
- If you need to add more fields later, just adjust the bit positions and update the encode/decode functions—just make sure total bits stay under 63.
内容的提问来源于stack exchange,提问作者LadislavBohm

