两种方法:
- 等概率得到0和1,然后利用二进制移位运算生成随机数
- 基于N * (randN - 1) + randN,可以等概率地生成1-N*N之间的数字
以 利用rand5得到rand7 为例说明
# 一个函数可以实现1-5的随机数,设计另一个函数,实现1-7的随机数
class Rand2rand:
def f5(self):
return int(random.random() * 5) + 1
# 等概率得到0和1
def g01(self):
while True:
tmp = self.f5()
if tmp < 3:
return 0
elif tmp > 3:
return 1
else:
continue
# 等概率得到0-6
def f06(self):
while True:
tmp = (self.g01() << 2) + (self.g01() << 1) + (self.g01() << 0)
if tmp == 7:
continue
else:
return tmp
# 等概率得到1-7
def f17(self):
return self.f06() + 1
# 验证结果
def testRes(self, testTimes: int, rand_generator):
arr = [0] * 7
for i in range(testTimes):
tmp = rand_generator()
arr[tmp - 1] += 1
for i in range(len(arr)):
print(f'{i + 1} 出现了 {arr[i]} 次')
def f17_2(self):
# 5*(self.f5()-1) 等概率产生 0, 5, 10, 15, 20
# self.f5() 等概率产生 1,2,3,4,5
# 想加后,等概率产生 1-25
# rand5()可以得到rand25()
# rand25()可以得到rand625()
# 总结,若randN() 可以随机生成1-N,那么N*(randN()-1) + randN() 可以随机生成 1-N**2
randVal = 22
while randVal > 21:
randVal = 5 * (self.f5() - 1) + self.f5()
return 1 + randVal % 7
# 结果验证
if __name__ == '__main__':
obj = Rand2rand()
rand_gen1 = obj.f17
rand_gen2 = obj.f17_2
obj.testRes(1000000, rand_gen2)
class Rand2randGeneral:
"""
更一般的问题,给定一个可以产出[min, max]之间的等概率随机数函数,
生成一个可以等概率生成[from, to]之间的随机数函数
"""
def __init__(self, min, max):
self.min = min
self.max = max
def randomBox(self):
diff = int(random.random() * (self.max - self.min + 1))
randomValue = self.min + diff
return randomValue
def getrand01(self):
size = self.max - self.min + 1
# 判断size 是奇数还是偶数
isOdd = True if (size & 1) != 0 else False
mid = int(size / 2)
while True:
ans = self.randomBox() - self.min
if isOdd and ans == mid:
continue
elif ans < mid:
return 0
else:
return 1
def getRandGeneral(self, fromValue, toValue):
if fromValue == toValue:
return fromValue
rangeVal = toValue - fromValue
num = 1
while (1 << num) - 1 < rangeVal:
num += 1
while True:
ans = 0
for i in range(num):
ans |= self.getrand01() << i
if ans > rangeVal:
continue
else:
return ans + fromValue