20位左右大整数转自定义字符短字符串压缩:16位以上整数解压精度异常修复方案求助
修复大整数压缩/解压的精度问题
问题根源
你的代码里的精度丢失完全是因为DeCompress方法中使用了Math.Pow——这个方法返回的是double类型,而double的有效精度只有15-17位。当处理16位以上的整数时,double无法准确表示这么大的数值,自然会出现舍入误差,导致解压后的结果和原数不符。
另外,你的Compress方法还有个小bug:循环条件code > 1会漏掉最后一次转换(比如当code等于你的符号列表长度时,会丢失最高位的1)。
修复后的代码
下面是修正后的完整实现,全程使用decimal进行整数运算,避免浮点数精度损失,同时修复了压缩逻辑的小问题:
private List<char> symbollist = new List<char> { '0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','x','y','z' }; private string Compress(decimal code) { if (code < 1) return "0"; List<char> charlist = new List<char>(); int baseCount = symbollist.Count; while (code > 0) { // 余数必定小于符号列表长度,直接转int安全 charlist.Add(symbollist[(int)(code % baseCount)]); code = decimal.Floor(code / baseCount); // 用Floor确保整数除法,避免小数干扰 } charlist.Reverse(); return new string(charlist.ToArray()); } private decimal DeCompress(string code) { if (code == "0") return 0; decimal codedec = 0; int baseCount = symbollist.Count; decimal currentPower = 1; // 从字符串末尾遍历,逐步累积幂次,避免浮点数运算 for (int i = code.Length - 1; i >= 0; i--) { int charIndex = symbollist.IndexOf(code[i]); if (charIndex == -1) throw new ArgumentException("Invalid character in code string"); codedec += charIndex * currentPower; currentPower *= baseCount; } return codedec; }
关键改进点
- 替换
Math.Pow为整数幂次累积:用currentPower变量逐步乘以符号列表长度,全程用decimal计算——decimal支持28-29位有效数字,完全能覆盖你的20位整数需求,彻底避免精度丢失。 - 修复压缩循环逻辑:把
code > 1改成code > 0,并使用decimal.Floor确保严格的整数除法,防止decimal的小数部分引发错误。 - 增加合法性校验:解压时检查字符是否在符号列表中,避免非法输入导致的异常。
替代方案
如果你的需求允许调整符号集,也可以考虑:
- 自定义Base-N编码框架:本质和当前实现逻辑一致,只要保持整数运算的核心,就能稳定处理任意长度的大整数(只要不超过
decimal的上限)。 - 使用
BigInteger类型:如果需要处理超过29位的超级大整数,可以把decimal换成System.Numerics.BigInteger,它支持无上限的整数运算,适配性更强。
测试你给出的异常案例:25478562549632547现在会被正确压缩,解压后能精准还原为原数,不会再出现精度偏差。
内容的提问来源于stack exchange,提问作者DAVidus
相关产品推荐
相关产品推荐

