将多个号码存储为一个唯一的号码

时间:2017-06-03 16:54:43

标签: php numbers primes bitmask

我有必要将许多号码(我可以决定哪些号码)存储为一个唯一的号码,我可以从中检索原始号码。
我已经知道了两种方法:

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的幂并将每个值相加

但是这两种方法快速增长(第一种方式比第二种方式快),使用素数要求我有很多素数。
有没有其他方法可以有效地执行此操作,例如,有一千个值?

3 个答案:

答案 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)

如果您的数字没有模式(因此可以通过某种方式进行压缩),实际上没有其他办法。

与素数不同,计算机解析数字也非常容易

预定值

@FlorainK评论指出我事实上我错过了

  

(我可以决定哪些数字)

唯一合理的解决方案是提供您的号码参考

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更容易使用。