[英]How can I optimize this 'lottery' function in PHP?
Earlier I wrote a code in Matlab for this sort of lottery function, just to test if it was possible. 早些时候,我在Matlab中为此类彩票功能编写了代码,只是为了测试是否可行。 However, I actually needed it in PHP so I've just rewritten the code and it does seem to work, but as it involves a lot of looping I want to make sure I'm doing it as efficiently as possible.
但是,实际上我在PHP中需要它,因此我只是重写了代码,它的确起作用了,但是由于涉及很多循环,因此我想确保自己尽可能高效地执行它。
What the code does: 代码的作用是:
You can call the function $lotto -> type($users,$difficulty)
and it will return two numbers. 您可以调用函数
$lotto -> type($users,$difficulty)
,它将返回两个数字。 Here's the explanation, $users
is the number of users registered on the website, ie the people who will potentially buy a ticket. 这就是解释,
$users
是在网站上注册的用户数,即可能购买票的人。 $difficulty
is a number between 1 and 10, where 5 is normal, 1 is easy and 10 is hard. $difficulty
是介于1和10之间的数字,其中5是正常值,1是简单值,而10是困难值。 Difficulty here means how hard it is to match all numbers on a lottery ticket. 这里的困难是指匹配彩票中的所有数字有多么困难。
So what are the numbers that the function returns? 那么函数返回的数字是多少? That would be
$n
and $r
. 那将是
$n
和$r
。 $n
is the amount of numbers there will be on the lottery ticket, and $r
is the amount of numbers you can choose from the lottery ticket. $n
是彩票上的数字数量, $r
是您可以从彩票中选择的数字数量。 For example, in the UK a national lottery ticket has 49 numbers if which you choose 6. Ie $n = 49
and $r = 6
. 例如,在英国,如果您选择6,则国家彩票有49个号码,即
$n = 49
和$r = 6
。
How does the function calculate these two numbers? 函数如何计算这两个数字? In the UK national lottery there are 13,983,816 different possible ticket combinations.
在英国国家彩票中,有13,983,816种可能的彩票组合。 If I were to run
$lotto -> type(13983816,1)
it would return array(49,6)
. 如果我运行
$lotto -> type(13983816,1)
,它将返回array(49,6)
。 Basically it tried to make it so there are as many combinations of tickets as there are registered users. 基本上,它试图做到这一点,因此,票证组合与注册用户一样多。
tl;dr, here's the code: tl; dr,代码如下:
<?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));
?>
I did a quick scan and spotted a few places that can be further optimized. 我进行了快速扫描,发现了一些可以进一步优化的地方。
Combination
组合
Your algorithm is a brute force one and can be further optimized 您的算法是蛮力的,可以进一步优化
private function nCr($n,$r){
return $this -> factorial($n) / (
$this->factorial($r) * $this->factorial($n - $r)
);
}
to 至
function nCr($n,$r) {
$top = 1;
$sub = 1;
for($i = $r+1; $i <= $n; $i++)
$top *= $i;
$n -= $r;
for($i = 2; $i <= $n; $i++)
$sub *= $i;
return $top / $sub;
}
Too Much Combination Calculation
组合计算过多
Calculate combination is expensive. 计算组合是昂贵的。
$u = 0;
$n = $r;
while($u < $users && $n < 50){
$u = $this -> nCr(++$n,$r);
}
to 至
$n = $r + 1;
$u = nCr($n, $r);
while ($u < $users && $n < 50) {
$n++;
$u *= $n;
$u /= ($n - $r);
}
An immediate observation is that you have the possibility of a divide by 0 error 立即观察到您有可能被0除以错误
$last_factor = $last_tickets_sold / $last_users;
Could be solved by putting a simple if statement around it 可以通过在其周围放一个简单的if语句来解决
$last_factor = ($last_users == 0) ? 0 : $last_tickets_sold / $last_users;
不管对代码进行详细检查,您确定循环都不需要继续或中断吗?
The range of factorial() in your algo is [0,50], so why not just precompute this statically? 您的算法中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];
}
}
Now add a self::genFactorial(50);
现在添加一个
self::genFactorial(50);
to __construct()
or to type()
and replace references to $this -> factorial($n)
by self::$factorial[$n]
. __construct()
或type()
并通过self::$factorial[$n]
替换对$this -> factorial($n)
的引用。
This is just a quick code dump; 这只是一个快速的代码转储。 not even compile checked so forgive any typos, etc. but what this does is to replace a function call (which includes a while loop) by an array element fetch.
甚至没有检查过编译,因此不能原谅任何错别字等。但这是通过数组元素提取来替换函数调用(包括while循环)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.