【问题标题】:Generate an unique and random integer生成唯一且随机的整数
【发布时间】:2017-06-06 16:43:08
【问题描述】:

我想创建具有 public_id 的用户帐户,它始终是唯一的整数随机(非增量)值。

我可以使用循环来检查随机整数是否唯一,但这似乎不是一个很好的解决方案。

我找到了一些字母数字生成器,我想我可以使用一些字符串到整数转换器将它们转换为整数,但是有没有特定于整数的方法?

我也担心可能的碰撞,但从长远来看,机会似乎总是存在的。(?)

【问题讨论】:

  • “我想制作....我可以转换它们” - 向我们展示您制作的内容,除非您需要指导或为您编写;是哪一个?

标签: php random integer unique


【解决方案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)来提高性能。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-03
        • 2010-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多