如何设计一个25%、75%的时间返回0、1的函数

184 阅读4分钟

给定一个50%的时间产生0、1的函数(就像现代编程语言中的大多数随机函数一样),我们如何设计一个25%、75%的时间返回0、1的函数?

让我们制定一个规则:不允许使用返回浮点的随机函数。我们只能使用上述的返回0,1的概率相同的函数,因为我们可以很容易地设置一个浮点作为阈值,并根据超过阈值的情况返回0,1。

📚内容

  1. 数学和概念
  2. 代码实现
  3. 复杂度
  4. 结果
  5. 挑战

数学和概念

让我们重温一下概率的基本数学知识。
给我们一个函数,它返回0,1的概率等于50%,我们把它命名为*P(0=50% & 1=50%),P(0)=0.5和.我们如何设计一个使用P(0=50% & 1=50%)

算法来实现上述题目?

为了设计P(0=25% & 1=75%),我们提出两种不同的方法。

OR运算法则

简而言之,我们可以进行一次OR运算来实现我们的目标。
P(0=25% & 1=75%) = P(0=50% & 1=50%) || P(0=50% & 1=50%)

||"运算符执行OR操作。下面是这种操作的所有结果。

  • 0 || 0 = 0
  • 0 || 1 = 1
  • 1 || 0 = 1
  • 1 || 1 = 1
    由于P(0=50% & 1=50%)以相同的概率分割出0、1,所以上述列表中的每一行都有25%的发生率(两个独立事件的概率的乘法)。因此,我们可以看到,它只有1/4的机会得到0,即25%。同时,它有75%的机会获得1。

位排他性OR运算法则

还有另一种方法来计算P(0=25% & 1=75%),即通过位移动和位排他性OR操作,它的伪代码如下:

function bitwiserand75():
    # either {0, 1}
    set x to rand50()

    # either {00, 10}
    x = x << 1

    # either {00, 01, 10, 11}
    # XOR operator, set each bit to 1 if only
    # one of two bits is 1
    x = x ^ rand50()

    if x > 0:
        return 1
    return 0

上述伪代码非常直接,但读者可能对XOR操作不是很熟悉。简而言之,如果两个比特中只有一个是1,它就会将每个比特设置为1。 以下是一些例子:

  • 00 ^ 00 = 00
  • 00 ^ 01 = 01
  • 10 ^ 00 = 10
  • 10 ^ 01 = 11

这样,我们就得到了所有0、1在两位数的二进制设置中的变异情况。看一下上面的列表,我们知道0,或00发生了4次中的1次,如果我们将返回1的阈值设置为大于0,我们有4次中的3次机会得到1,因此是75%。

🖥️代码实现

下面是实现上节所述两种算法的代码:

import random

class baisedGenerator:
    # Generator with 50% of 0 and 1
    def rand50(self):
        return random.randint(0, 1)
    
    # Associated with OR operator
    # Generator with 75% of 0 and 1
    def rand75(self):
        return self.rand50() or self.rand50()

    # Associated with bitwise shifting operator
    # Generator with 75% of 0 and 1 by bitwise shifting
    def bitwiserand75(self):
        x = self.rand50()
        x = x << 1
        x = x ^ self.rand50()
        if x > 0:
            return 1
        return 0

⏳复杂度

时间复杂性

上述两种方法具有恒定的运行时间复杂度,因为python的随机模块在恒定的时间内给出一个随机的(0,1),所有的乘法、移位和XOR操作都需要O(1)来运行。

空间复杂度

上述两种方法的 baised 生成器不需要额外的内存,因此辅助空间不变

✍🏻结果

人们可以通过声明一个简单的for循环简单地汇总结果,但要打印出结果:

g = baisedGenerator()

for i in range(1, 101):
    print(g.rand75(), end=" ")
    if i%10 == 0:
        print()    
print()

for i in range(1, 101):
    print(g.bitwiserand75(), end=" ")
    if i%10 == 0:
        print()

这里是结果,100个中大约有75%的人认为这两种方法都会打印出1:

1 1 1 1 1 1 1 0 1 0 
1 0 1 0 1 1 1 1 1 1 
0 1 0 1 1 1 0 1 0 1 
1 1 1 1 0 1 1 1 1 0 
1 1 1 0 0 0 0 1 1 1 
1 1 1 1 1 0 1 0 0 1 
1 1 1 1 1 1 0 1 1 1 
0 0 1 1 1 1 1 1 1 0 
0 1 1 1 1 1 1 1 1 1 
0 1 1 1 1 0 1 1 0 1 

1 1 0 0 0 0 1 1 1 1 
0 1 1 1 0 1 1 1 0 1 
1 0 1 1 1 0 1 1 1 1 
1 1 1 1 1 1 0 1 1 0 
0 0 1 1 0 0 1 1 1 1 
1 1 1 1 1 1 1 1 1 0 
1 0 1 0 1 1 0 1 1 1 
1 1 1 1 1 1 1 1 1 1 
1 1 0 0 0 1 1 1 1 1 
0 1 1 1 1 1 1 0 1 1 

通过OpenGenus的这篇文章,你一定对如何以25%和75%的概率生成0和1有了完整的了解。

🧠挑战

给你,一个简单的基于非浮动点的 baised 生成器,它给出了25%和75%的0和1,但是你能用AND运算符代替OR运算符来生成相同的0和1的分布吗,假设其他规则不变?