给定一个函数,它产生的是1到5之间的随机整数,写一个函数,它产生的是1到7之间的随机整数。
当前回答
int randbit( void )
{
while( 1 )
{
int r = rand5();
if( r <= 4 ) return(r & 1);
}
}
int randint( int nbits )
{
int result = 0;
while( nbits-- )
{
result = (result<<1) | randbit();
}
return( result );
}
int rand7( void )
{
while( 1 )
{
int r = randint( 3 ) + 1;
if( r <= 7 ) return( r );
}
}
其他回答
int randbit( void )
{
while( 1 )
{
int r = rand5();
if( r <= 4 ) return(r & 1);
}
}
int randint( int nbits )
{
int result = 0;
while( nbits-- )
{
result = (result<<1) | randbit();
}
return( result );
}
int rand7( void )
{
while( 1 )
{
int r = randint( 3 ) + 1;
if( r <= 7 ) return( r );
}
}
这个怎么样
rand5 () % + rand5 (2) + 2 (2) % + rand5 rand5 () (2) % + rand5 % + rand5 (2) 2
不确定这是均匀分布的。有什么建议吗?
function rand7() {
while (true) { //lowest base 5 random number > 7 reduces memory
int num = (rand5()-1)*5 + rand5()-1;
if (num < 21) // improves performance
return 1 + num%7;
}
}
Python代码:
from random import randint
def rand7():
while(True):
num = (randint(1, 5)-1)*5 + randint(1, 5)-1
if num < 21:
return 1 + num%7
100000次运行的测试分布:
>>> rnums = []
>>> for _ in range(100000):
rnums.append(rand7())
>>> {n:rnums.count(n) for n in set(rnums)}
{1: 15648, 2: 15741, 3: 15681, 4: 15847, 5: 15642, 6: 15806, 7: 15635}
我想我有四个答案,两个给出了像@Adam Rosenfield那样的精确解决方案,但没有无限循环问题,另外两个几乎完美的解决方案,但执行速度比第一个更快。
最好的精确解决方案需要7次调用rand5,但为了理解,让我们继续。
方法一:精确
Adam的答案的优点在于它给出了一个完美的均匀分布,并且只需要两次调用rand5()的概率非常高(21/25)。然而,最坏的情况是无限循环。
下面的第一个解决方案也给出了一个完美的均匀分布,但总共需要对rand5进行42次调用。没有无限循环。
下面是一个R的实现:
rand5 <- function() sample(1:5,1)
rand7 <- function() (sum(sapply(0:6, function(i) i + rand5() + rand5()*2 + rand5()*3 + rand5()*4 + rand5()*5 + rand5()*6)) %% 7) + 1
对于不熟悉R的人,这里是一个简化版本:
rand7 = function(){
r = 0
for(i in 0:6){
r = r + i + rand5() + rand5()*2 + rand5()*3 + rand5()*4 + rand5()*5 + rand5()*6
}
return r %% 7 + 1
}
rand5的分布将被保留。如果我们计算一下,循环的7次迭代中的每一次都有5^6个可能的组合,因此可能组合的总数为(7 * 5^6)%% 7 = 0。因此,我们可以将生成的随机数分成7个相等的组。有关这方面的更多讨论,请参见方法二。
以下是所有可能的组合:
table(apply(expand.grid(c(outer(1:5,0:6,"+")),(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
15625 15625 15625 15625 15625 15625 15625
我认为这很容易证明亚当的方法运行得快得多。在Adam的解中有42次或更多的rand5调用的概率非常小((4/25)^21 ~ 10^(-17))。
方法2 -不精确
现在是第二个方法,它几乎是统一的,但需要6次调用rand5:
rand7 <- function() (sum(sapply(1:6,function(i) i*rand5())) %% 7) + 1
以下是一个简化版本:
rand7 = function(){
r = 0
for(i in 1:6){
r = r + i*rand5()
}
return r %% 7 + 1
}
这实际上是方法1的一次迭代。如果我们生成所有可能的组合,结果计数如下:
table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
2233 2232 2232 2232 2232 2232 2232
一个数字将在5^6 = 15625次试验中再次出现。
现在,在方法1中,通过将1加到6,我们将数字2233移动到每个连续的点上。因此,组合的总数将匹配。这是可行的,因为5^ 6% % 7 = 1,然后我们做了7个适当的变化,所以(7 * 5^ 6% % 7 = 0)。
方法三:精确
如果理解了方法1和2的参数,接下来就是方法3,它只需要7次调用rand5。在这一点上,我觉得这是精确解决方案所需的最少调用数。
下面是一个R的实现:
rand5 <- function() sample(1:5,1)
rand7 <- function() (sum(sapply(1:7, function(i) i * rand5())) %% 7) + 1
对于不熟悉R的人,这里是一个简化版本:
rand7 = function(){
r = 0
for(i in 1:7){
r = r + i * rand5()
}
return r %% 7 + 1
}
rand5的分布将被保留。如果我们计算一下,循环的7次迭代中的每一次都有5个可能的结果,因此可能组合的总数为(7 * 5)%% 7 = 0。因此,我们可以将生成的随机数分成7个相等的组。有关这方面的更多讨论,请参见方法一和方法二。
以下是所有可能的组合:
table(apply(expand.grid(0:6,(1:5)),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
5 5 5 5 5 5 5
我认为这很直接地证明了亚当的方法仍然运行得更快。在Adam的解中有7次或更多的rand5调用的概率仍然很小((4/25)^3 ~ 0.004)。
方法4 -不精确
这是第二种方法的一个小变化。它几乎是统一的,但需要7次调用rand5,这是一个额外的方法2:
rand7 <- function() (rand5() + sum(sapply(1:6,function(i) i*rand5())) %% 7) + 1
以下是一个简化版本:
rand7 = function(){
r = 0
for(i in 1:6){
r = r + i*rand5()
}
return (r+rand5()) %% 7 + 1
}
如果我们生成所有可能的组合,结果计数如下:
table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6,1:5),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
11160 11161 11161 11161 11161 11161 11160
在5^7 = 78125次试验中,有两个数字会少出现一次。在大多数情况下,我可以接受。
在php中
function rand1to7() {
do {
$output_value = 0;
for ($i = 0; $i < 28; $i++) {
$output_value += rand1to5();
}
while ($output_value != 140);
$output_value -= 12;
return floor($output_value / 16);
}
循环生成16到127之间的随机数,除以16生成1到7.9375之间的浮点数,然后舍入得到1到7之间的整数。如果我没记错的话,得到7个结果中的任何一个的概率都是16/112。