如何将Decimal类型转换为支持字典序排序的字节数组?
如何将Decimal类型转换为支持字典序排序的字节数组?
好问题!你已经发现double类型可以通过反转BitConverter.GetBytes的结果,得到能按字典序和原正数数值序一致排序的字节数组,现在想对decimal做同样的操作对吧?这确实需要费点功夫,因为decimal的内部存储结构和double完全不一样——double是IEEE754浮点数格式,而decimal是为十进制精确计算设计的128位结构,由96位整数、符号位和缩放因子共同组成。
要实现目标,我们得手动构造符合要求的字节数组,核心思路是把decimal的各个组成部分按数值序对应字典序的规则重新编排,具体步骤和代码如下:
实现思路拆解
- 先通过
decimal.GetBits获取decimal的内部组成信息:这个方法返回一个包含4个int的数组,其中前三个int拼接成96位的整数部分,第四个int的最高位是符号位(0为正,1为负),低16位是缩放因子(0-28,表示小数点后的位数)。 - 符号位处理:为了让正数的字节数组字典序大于负数,同时负数中数值大的(比如-1)比数值小的(比如-2)字节数组字典序更大,我们给正数的前缀字节设为
0x00,负数设为0xFF,并且对负数的整数部分按位取反。 - 缩放因子处理:缩放因子越大,
decimal的实际数值越小(比如123.45缩放是2,12345缩放是0,后者数值更大),所以用28 - 缩放因子来转换,让缩放小的(数值大的)对应的字节更大。 - 整数部分处理:把96位整数转成大端字节序,保证高位字节在前,符合字典序从左到右比较的逻辑。
完整代码示例
public static byte[] DecimalToSortableBytes(decimal d) { int[] bits = decimal.GetBits(d); bool isNegative = (bits[3] & 0x80000000) != 0; int scale = (bits[3] >> 16) & 0x00FF; // 将96位整数部分转换为大端字节序 byte[] intBytes = new byte[12]; Buffer.BlockCopy(BitConverter.GetBytes(bits[2]), 0, intBytes, 0, 4); Buffer.BlockCopy(BitConverter.GetBytes(bits[1]), 0, intBytes, 4, 4); Buffer.BlockCopy(BitConverter.GetBytes(bits[0]), 0, intBytes, 8, 4); // 小端系统下调整每个32位块的字节顺序,统一为大端 if (BitConverter.IsLittleEndian) { Array.Reverse(intBytes, 0, 4); Array.Reverse(intBytes, 4, 4); Array.Reverse(intBytes, 8, 4); } // 调整缩放因子,保证数值大的decimal对应更大的字节 byte scaleByte = (byte)(28 - scale); byte[] result = new byte[14]; if (isNegative) { // 负数的整数部分按位取反,确保数值大的负数字典序更大 for (int i = 0; i < intBytes.Length; i++) { intBytes[i] = (byte)~intBytes[i]; } result[0] = 0xFF; } else { result[0] = 0x00; } result[1] = scaleByte; Buffer.BlockCopy(intBytes, 0, result, 2, 12); return result; }
验证逻辑
比如你测试2.0m、2.05m、2.1m这几个正数,得到的字节数组会按字典序从小到大排列,和它们的数值顺序完全一致;如果测试-2.1m、-2.05m、-2.0m,得到的字节数组也会按字典序从小到大排列,对应数值从-2.1到-2.0的递增顺序。
备注:内容来源于stack exchange,提问作者ren
相关产品推荐
相关产品推荐

