如何优化此';彩票';PHP中的函数?

如何优化此';彩票';PHP中的函数?,php,optimization,combinations,Php,Optimization,Combinations,早些时候,我在Matlab中为这种彩票函数编写了一个代码,只是为了测试它是否可行。然而,我实际上需要在PHP中使用它,所以我刚刚重写了代码,它看起来确实有效,但由于它涉及大量循环,我希望确保我尽可能高效地完成它 代码的作用: 您可以调用函数$lotto->type($users,$defestion),它将返回两个数字。下面的解释是,$users是在网站上注册的用户数,即可能购买门票的用户$Demobility是一个介于1和10之间的数字,其中5是正常值,1是容易值,10是难值。这里的困难意味着

早些时候,我在Matlab中为这种彩票函数编写了一个代码,只是为了测试它是否可行。然而,我实际上需要在PHP中使用它,所以我刚刚重写了代码,它看起来确实有效,但由于它涉及大量循环,我希望确保我尽可能高效地完成它

代码的作用:

您可以调用函数
$lotto->type($users,$defestion)
,它将返回两个数字。下面的解释是,
$users
是在网站上注册的用户数,即可能购买门票的用户<代码>$Demobility是一个介于1和10之间的数字,其中5是正常值,1是容易值,10是难值。这里的困难意味着匹配彩票上的所有数字有多难

那么函数返回的数字是什么呢?这将是
$n
$r
$n
是彩票上的数字量,
$r
是您可以从彩票中选择的数字量。例如,在英国,一张国家彩票有49个号码,如果你选择6。即
$n=49
$r=6

函数如何计算这两个数字?英国国家彩票有13983816种不同的彩票组合。如果我运行
$lotto->type(13983816,1)
它将返回
数组(49,6)
。基本上,它试图做到这一点,因此有尽可能多的组合票有注册用户

tl;博士,这是代码:

<?php
class lotto {
    public function type($users,$difficulty){
        $current_r = $r = 2;
        $current_n = 0;
        $difficulty = ($difficulty + 5) / 10; // sliding scale from 1 - 10
        $last_tickets_sold = 200; // tickets sold in last lotto
        $last_users = 100; // how many users there were in the last lotto
        $last_factor = $last_tickets_sold / $last_users; // tickets per user
        $factor = $last_factor * $difficulty;
        $users *= $factor;
        while($r <= 10){
            $u = 0;
            $n = $r;
            while($u < $users && $n < 50){
                $u = $this -> nCr(++$n,$r);
            }
            if($r == 2){
                $current_n = $n;
            } elseif(abs($this -> nCr($n,$r) - $users) < abs($this -> nCr($current_n,$current_r) - $users)){
                // this is a better match so update current n and r
                $current_r = $r;
                $current_n = $n;
            }
            $r++;
        }
        return array($current_n,$current_r);
    }
    private function nCr($n,$r){
        return $this -> factorial($n) / (
            $this -> factorial($r) * $this -> factorial($n - $r)
        );
    }
    private function factorial($x){
        $f = $x;
        while(--$x){
            $f *= $x;
        }
        return $f;
    }
}
$lotto = new lotto;
print_r($lotto -> type(1000,5));
?>

一个直接的观察结果是,您有可能出现被0除的错误

$last_factor = $last_tickets_sold / $last_users;
可以通过在其周围放置一个简单的if语句来解决

$last_factor = ($last_users == 0) ? 0 : $last_tickets_sold / $last_users;

一个直接的观察结果是,您有可能出现被0除的错误

$last_factor = $last_tickets_sold / $last_users;
可以通过在其周围放置一个简单的if语句来解决

$last_factor = ($last_users == 0) ? 0 : $last_tickets_sold / $last_users;

无论您对代码进行了详细检查,您确定循环不需要继续或中断吗?

无论您对代码进行了详细检查,您确定您的循环不需要继续或中断吗?

我进行了快速扫描,发现了一些可以进一步优化的地方

组合
您的算法是蛮力算法,可以进一步优化

private function nCr($n,$r){
    return $this -> factorial($n) / (
        $this->factorial($r) * $this->factorial($n - $r)
    );
}

功能nCr($n,$r){
$top=1;
$sub=1;

对于($i=$r+1;$i我做了一次快速扫描,发现了一些可以进一步优化的地方

组合
您的算法是蛮力算法,可以进一步优化

private function nCr($n,$r){
    return $this -> factorial($n) / (
        $this->factorial($r) * $this->factorial($n - $r)
    );
}

功能nCr($n,$r){
$top=1;
$sub=1;

对于($i=$r+1;$i来说,factorial()在您的算法中的范围是[0,50],那么为什么不只是静态地预计算呢

private static $factorial=array(1);

private static genFactorial($max) {
    if( count( self::$factorial ) > $max ) return;
    foreach ( range(count(self::$factorial), $max) as $n ) {
        self::$factorial[$n] = $i*self::$factorial[$n-1];
    }
}
现在将一个
self::genFactorial(50);
添加到
\uu construct()
type()
,并将对
$this->factorial($n)
的引用替换为
self::$factorial[$n]


这只是一个快速的代码转储;甚至没有编译检查,所以请原谅任何打字错误等。但这只是用数组元素获取来替换函数调用(包括while循环)。

在您的算法中,阶乘()的范围是[0,50],那么为什么不只是静态地预计算呢

private static $factorial=array(1);

private static genFactorial($max) {
    if( count( self::$factorial ) > $max ) return;
    foreach ( range(count(self::$factorial), $max) as $n ) {
        self::$factorial[$n] = $i*self::$factorial[$n-1];
    }
}
现在将一个
self::genFactorial(50);
添加到
\uu construct()
type()
,并将对
$this->factorial($n)
的引用替换为
self::$factorial[$n]


这只是一个快速的代码转储;甚至没有编译检查,所以请原谅任何打字错误,等等。但这样做是为了替换一个函数调用(包括一个while循环)通过数组元素获取。

一个小优化是将阶乘的先前结果存储在数组中,这样您就不必每次都进行长时间的计算。这将映射输入=>输出的映射。这将大大减少阶乘的处理时间。您还可以存储最后一个已知值,因为您有两个始终递增的值单数。一个小优化是将阶乘的先前结果存储在一个数组中,这样您就不必每次都进行长时间的计算。这将映射输入=>输出的映射。这将大大减少阶乘的处理时间。您还可以存储上一个已知值,因为您有两个始终递增的数字。但是
$last_users=100;
,一个静态定义的值。如果这产生一个除以0的错误,这将是一个史诗般的PHP错误。同意,但我假设(是的,我知道,假设是错误的),这些值将被更改为从数据库中提取的动态值。但是,是的,考虑到当前代码,这是不可能的。只是观察您的假设是正确的,它将从数据库中提取,但是有可能上次有0个用户使用了彩票,因此感谢您的建议。但是
$last\u users=100;
,一个静态定义的值。如果这产生了除以0的错误,那将是一个史诗般的PHP错误。同意,但我假设(是的,我知道,假设是错误的),这些值将被更改为从数据库中提取的动态值。但是,是的,考虑到当前的代码,这是不可能的。只是一个观察您的假设是正确的,它将从数据库中提取,但是有可能上次有0个用户使用了彩票,因此感谢您的建议。绝对不会,他们只会按照高达n=50和r=10,我需要尝试每种可能性以获得更好的匹配。当然不是,它们只高达n=50和r=10,我需要尝试每种可能性以获得更好的匹配。我没有机会检查这些输出以与OP的代码配合,但这是问题的唯一答案。很好,刚刚对befo进行了基准测试回复和回复:100x原创~=.159秒100x新代码~=.0174秒显著改进,非常感谢:),我已经更新了你的评论。没有机会检查这些的输出以与OP的合作