我有必要将许多号码(我可以决定哪些号码)存储为一个唯一的号码,我可以从中检索原始号码。
我已经知道了两种方法:
1)算术的基本定理(素数)
假设我有5个值,我为每个值分配一个素数而不是1
a = 2
b = 3
c = 5
d = 7
e = 13
如果我想存储a,b和ci可以将它们相乘2*3*5=30
并且我知道没有其他的素数产品可以是30.然后检查一个值是否包含,例如,b,我需要的全部是30 % b == 0
2)位掩码 就像Linux权限一样,使用2的幂并将每个值相加
但是这两种方法快速增长(第一种方式比第二种方式快),使用素数要求我有很多素数。
有没有其他方法可以有效地执行此操作,例如,有一千个值?
答案 0 :(得分:1)
当你有千的价值时,还有其他方法可以有效地做到这一点吗?
我不是数学家,但它是基本数学,全部取决于范围
范围0-1:您想要存储4个数字0-1 - 它基本上是二进制系统
Number1 + Number2 * 2^1 + Number3 * 2^2 + Number4 * 2^3
范围0-50 您想要存储4个数字0-49
Number1 + Number2 * 50^1 + Number3 * 50^2 + Number4 * 50^3
范围0-X 您想要存储N个数字0-X
Number1 + Number2 * (X+1)^1 + Number3 * (X+1)^2 + ... + NumberN * (X+1)^(N-1)
如果您的数字没有模式(因此可以通过某种方式进行压缩),实际上没有其他办法。
与素数不同,计算机解析数字也非常容易
(我可以决定哪些数字)
唯一合理的解决方案是提供您的号码参考
0 is 15342
1 is 6547
2 is 76234
3 is "i like stack overflow"
4 is 42141
所以你将工作范围0-4
(5个选项)和任何组合长度。在“编码”和“解码”数字时使用参考
一千个值?
所以您将使用范围0-999
0 is 62342
1 is 7456345653
2 is 45656234532
...
998 is 7623452
999 is 4324234326453
假设您使用的64位系统和编程/ db语言与64位整数一起使用
2^64 = 18446744073709551616
您的最大范围是1000^X < 18446744073709551616
,其中X
是您可以存储在一个64位整数中的数字数
这只是6。
您只能存储6个单独的数字0-999,这些数字将适合一个64位整数。
0,0,0,0,0,0 is 0
1,0,0,0,0,0 is 1
0,1,0,0,0,0 is 1000
999,999,999,999,999,999 is ~1e+18
答案 1 :(得分:1)
好的,所以你要存储&#34; a,b,c&#34;或&#34; a,b&#34;或&#34; a,b,c,d&#34;或&#34; a&#34;等(感谢@FlorianK)
在这种情况下,只能使用按位运算符和两个幂
$a = 1 << 0; // 1
$b = 1 << 1; // 2
$c = 1 << 2; // 4
$d = 1 << 3; // 8
.. etc
让我们说$flag
有$a
和$c
$flag = $a | $c; // $flag is integer here
现在检查
$ok = ($flag & $a) && ($flag & $c); // true
$ok = ($flag & $a) && ($flag & $b); // false
所以在64位系统/语言/操作系统中你最多可以使用64个标志,这样可以得到2 ^ 64个组合
没有其他选择。质数要差得多,因为你跳过了许多数字,而二元系统使用每一个数字。
我发现您正在使用数据库,并且您希望将其存储在数据库中。
我真的认为我们正在处理XY Problem,你应该重新考虑你的申请而不是做出这样的解决方法。
答案 2 :(得分:1)
如果您要存储10个基数,则通过基数11进行转换。随着基数的增加,您将获得额外的“数字”。使用该数字作为分隔符。因此,三个基数10“10,42,457”变为“10A42A457”:一个基数为11的数字(以“A”作为附加数字)。
无论您的原始数字是什么基数,请将基数增加1并连接,使用额外数字作为分隔符。这将为您提供增加基数的单个数字。
该单个数字可以存储在您认为方便的任何数字基数中:例如二进制,denary或hex。
要检索原始数字,只需转换为基数11(或其他),然后用分隔符替换额外的数字。
ETA:您不必使用基数11.单个数字“10A42A457”也是有效的十六进制数,因此可以使用任何11或更高的基数。十六进制可能比基础11更容易使用。