将非常大的整数压缩成尽可能小的字符串
Compress very large Integers into smallest possible string
我想将整数(~20 位数字)压缩为带有符号的较小字符串。
我成功了,但它只适用于大约 16 位以下的整数。
我猜这是某种舍入错误。有谁知道如何修复它,或者使用其他方法将整数压缩为带有自定义字符的字符串?
提前致谢!
示例:
两种方式都有效:
822152842686533 => 6OKYXLtml
6OKYXLtml => 822152842686533
两种方式都不起作用:
25478562549632547 => 3OxGclFmZ9
3OxGclFmZ9 => 25478562549632553
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";
string codestring = "";
List<char> charlist = new List<char>();
while (code > 1)
{
charlist.Add(symbollist[(int)(code % symbollist.Count)]);
code /= symbollist.Count;
}
for (int i = charlist.Count-1; i >=0; i--)
{
codestring += charlist[i];
}
return codestring;
}
private decimal DeCompress(string code)
{
decimal codedec = 0;
for (int i = 0; i < code.Length; i++)
{
codedec += symbollist.IndexOf(code[i]) * (decimal)System.Math.Pow(symbollist.Count, code.Length - 1 - i);
}
return codedec;
}
因为您的 System.Math.Pow
使用的是 double
,而不是 decimal
,并且对于您较大的数字而言精度不够。 double
只有 52 位的尾数,而你的第二个例子是一个 55 位的整数。
反正你不需要幂函数,编码的时候也不需要反转数字。按照您生成它们的顺序,首先用最低有效数字编码。然后解码的时候,每次乘以基数,维护一个基数的n次方。添加时使用它来乘以每个数字。使用 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)
{
string codestring = "";
do
{
codestring += symbollist[(int)(code % symbollist.Count)];
code = Decimal.Floor(code / symbollist.Count);
} while (code >= 1);
return codestring;
}
private decimal DeCompress(string code)
{
if (code.Length == 0)
return 0;
decimal codedec = symbollist.IndexOf(code[0]);
decimal pos = 1;
for (int i = 1; i < code.Length; i++)
{
pos *= symbollist.Count;
codedec += symbollist.IndexOf(code[i]) * pos;
}
return codedec;
}
示例输入、编码、解码(使用 decimal
类型的所有尾数位):
79228162514264337593543950335
b8NYXtnuNafbQGBo4
79228162514264337593543950335
(注意:您的代码应该对分数的存在做一些处理。要么在编码之前删除分数,要么 return 出错。还要处理无效数字。)
我想将整数(~20 位数字)压缩为带有符号的较小字符串。 我成功了,但它只适用于大约 16 位以下的整数。
我猜这是某种舍入错误。有谁知道如何修复它,或者使用其他方法将整数压缩为带有自定义字符的字符串?
提前致谢!
示例:
两种方式都有效:
822152842686533 => 6OKYXLtml
6OKYXLtml => 822152842686533
两种方式都不起作用:
25478562549632547 => 3OxGclFmZ9
3OxGclFmZ9 => 25478562549632553
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";
string codestring = "";
List<char> charlist = new List<char>();
while (code > 1)
{
charlist.Add(symbollist[(int)(code % symbollist.Count)]);
code /= symbollist.Count;
}
for (int i = charlist.Count-1; i >=0; i--)
{
codestring += charlist[i];
}
return codestring;
}
private decimal DeCompress(string code)
{
decimal codedec = 0;
for (int i = 0; i < code.Length; i++)
{
codedec += symbollist.IndexOf(code[i]) * (decimal)System.Math.Pow(symbollist.Count, code.Length - 1 - i);
}
return codedec;
}
因为您的 System.Math.Pow
使用的是 double
,而不是 decimal
,并且对于您较大的数字而言精度不够。 double
只有 52 位的尾数,而你的第二个例子是一个 55 位的整数。
反正你不需要幂函数,编码的时候也不需要反转数字。按照您生成它们的顺序,首先用最低有效数字编码。然后解码的时候,每次乘以基数,维护一个基数的n次方。添加时使用它来乘以每个数字。使用 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)
{
string codestring = "";
do
{
codestring += symbollist[(int)(code % symbollist.Count)];
code = Decimal.Floor(code / symbollist.Count);
} while (code >= 1);
return codestring;
}
private decimal DeCompress(string code)
{
if (code.Length == 0)
return 0;
decimal codedec = symbollist.IndexOf(code[0]);
decimal pos = 1;
for (int i = 1; i < code.Length; i++)
{
pos *= symbollist.Count;
codedec += symbollist.IndexOf(code[i]) * pos;
}
return codedec;
}
示例输入、编码、解码(使用 decimal
类型的所有尾数位):
79228162514264337593543950335
b8NYXtnuNafbQGBo4
79228162514264337593543950335
(注意:您的代码应该对分数的存在做一些处理。要么在编码之前删除分数,要么 return 出错。还要处理无效数字。)