生成唯一且随机的整数
Posted
技术标签:
【中文标题】生成唯一且随机的整数【英文标题】:Generate an unique and random integer 【发布时间】:2017-06-06 16:43:08 【问题描述】:我想创建具有 public_id 的用户帐户,它始终是唯一的整数随机(非增量)值。
我可以使用循环来检查随机整数是否唯一,但这似乎不是一个很好的解决方案。
我找到了一些字母数字生成器,我想我可以使用一些字符串到整数转换器将它们转换为整数,但是有没有特定于整数的方法?
我也担心可能的碰撞,但从长远来看,机会似乎总是存在的。(?)
【问题讨论】:
“我想制作....我可以转换它们” - 向我们展示您制作的内容,除非您需要指导或为您编写;是哪一个? 【参考方案1】:您可以使用像 mt_rand 这样的原生 php 函数之一,或者使用更可靠的方式 - 基于 microtime 函数生成整数。
为确保该值是唯一的,您需要在 DB 中的列上添加唯一索引并写入“ON DUPLICATE UPDATE”以插入/更新查询,如果该值不是唯一的,则会向该值添加一些数字
【讨论】:
【参考方案2】:您可以使用带有大句号的linear congruential generator。
这是一个生成唯一整数的方法,它总是有 6 位数字。在生成 100000 到 996722 之间的所有数字之前,它不会生成重复,这为您提供了近 900 000 个不同的数字。
条件是你可以为函数提供它最后生成的数字。因此,如果您将数字存储在数据库中,则必须以某种方式检索最后分配的数字,以便将其提供给此函数:
function random_id($prev)
return 100000 + (($prev-100000)*97 + 356563) % 896723;
$prev = 100000; // must be a 6 digit number: the initial seed.
// Generate the first 10 pseudo-random integers.
for ($i = 0; $i < 10; $i++)
$prev = random_id($prev);
echo $prev . "\n";
前 10 个数字的上述生成产生:
456563
967700
331501
494085
123719
963860
855744
232445
749606
697735
您可以按照参考文章中关于在线性同余生成器中获取 完整周期 中的规则对其他范围执行此操作。具体来说,如果要生成具有 n 个数字的数字,其中第一个数字不能为零(因此介于 10n-1 和 10n -1),然后我发现最容易找到一个刚好低于 9⋅10n-1 的大素数作为公式的最后一个数字。其他两个数字可以是任何正整数,但最好保持第一个较小以避免溢出。
但是,PHP 整数仅限于 PHP_INT_MAX
(通常为 2147483647),因此对于 10 位或更多位的数字,您需要使用浮点运算符。那时不应使用 %
运算符。请改用fmod
。
例如,要生成 12 位数字,您可以使用以下公式:
function random_id($prev)
return 100000000000 + fmod((($prev-100000000000)*97 + 344980016453), 899999999981);
$prev = 100000000000; // must be a 12 digit number: the initial seed.
// Generate the first 10 pseudo-random integers.
for ($i = 0; $i < 10; $i++)
$prev = random_id($prev);
echo $prev . "\n";
【讨论】:
如果我想要一个 12 位整数,应该怎么做? 我添加了更多信息来生成 n 位数字,并提供了 12 位数字的代码。如果此答案适合您的需求,请mark it as accepted。 最好使用像openssl_random_pseudo_bytes
这样的实际加密随机源。滚动您自己的随机数生成器并不是一个好主意。
@tadman,这个问题的要求不是产生加密随机数,而是产生具有完整周期的(伪)随机数,即。在生成所有可用数字之前,保证不会产生相同的数字。显然,这使得在这样一个时期结束时生成的数字几乎不是随机的:您可以预测该系列的最后一个。但这是这里的要求。
这不是问题本身所说的。它说随机和独特。给定足够的位,任何足够随机的源都将具有最小的冲突。 64 位值不太可能发生冲突。假设 PRNG 足够健壮,256 位值可能永远不会发生冲突。【参考方案3】:
使用 timeStamp 确实会做得很好,因为它使用时间来生成随机数。您还可以将以下函数与其他随机生成的数字连接起来。
function passkey($format = 'u', $utimestamp = null)
if (is_null($utimestamp))
$utimestamp = microtime(true);
$timestamp = floor($utimestamp);
$milliseconds = round(($utimestamp - $timestamp) * 1000000);
return date(preg_replace('`(?<!\\\\)u`', $milliseconds, $format),$timestamp);
echo passkey(); // 728362
【讨论】:
【参考方案4】:有两种可能的解决方案:
1) 如果你的“长期”真的很长 - 这意味着这是 可能,您已经用完了 PHP_INT_MAX 并且没有 only-integer-specific 方式。
2) 如果您没有超出 PHP_INT_MAX - 那么您需要一些存储空间 检查ID。
如果是 1,您可以使用库 hashids。为避免冲突 - 您需要在输入时添加一些增量计数器。然后您可以将字符串按每个字母转换回整数。
如果是 2 - 您可以使用一些内存数据库(如 redis)来提高性能。
【讨论】:
以上是关于生成唯一且随机的整数的主要内容,如果未能解决你的问题,请参考以下文章
如何生成一个不以 0 开头且具有唯一数字的随机 4 位数字?