我想知道是否有一种方法可以在特定范围内生成递减的数字?我希望编程能够持续输出直到达到0,且该范围中最大的数字必须是正数。
例如,如果范围为(0,100),则可能的输出如下: 96 57 43 23 9 0
对于我原始帖子所造成的混淆,请谅解。
例如,如果范围为(0,100),则可能的输出如下: 96 57 43 23 9 0
对于我原始帖子所造成的混淆,请谅解。
我会生成n个随机数,然后将它们从高到低排序。
X>0
开始,并在每个步骤中从(0,X)
中选择一个随机数并将X
替换为它的算法是不好的。为什么?因为(假设random
行为正常)每个步骤的期望值都在区间(0,X)
的中间。这意味着这些数字的序列预计会尽快收敛于0
,即(1/2)^N
。事实上,可以很容易地看到大多数数字都接近0
,即使对于极大的初始值也是如此。这意味着这些数字的分布不均匀,这通常是所需的属性。N
个数字的复杂度为O(N)
,而且(更重要的是)内存使用量为O(1)
,这仍然是一个主要缺点。N
个随机数并对它们进行排序。虽然这不错,但该算法的复杂度为O(N log(N))
(或者与底层排序算法的复杂度相同),如果我们按顺序放置元素而不是排序,则可以将其降低到O(N)
,但内存使用量为O(N)
——我们必须记住所有元素。然而,这些数字将均匀分布,这是一个巨大的优势!根据Jon Louis Bentley在论文“生成排序的随机数列表”中的想法,以下算法可能是最优的(至少在我所知道的范围内),并且产生均匀分布的数字:import math
import random
def generate( min = 0, max = 10, number = 100 ):
start = 0
for i in xrange( number, 0, -1 ):
start = start + math.log( random.random( ) ) / i
next = math.exp( start ) * ( max - min ) + min
yield next
for number in generate( ):
print number
O(N)
(我怀疑无法更低),但内存使用量为O(1)
,这些数字均匀分布在区间(min,max)
中,这一点并不明显,但却是真实的。唯一的缺点是我们必须知道要生成多少个数字才能开始。next
的整数部分,并且仅在它与先前产生的next
值不同时这样做。但是,您将失去对要获取多少个整数的控制,但由于分布仍然是均匀的,因此您肯定会得到一些。因此,如果您想对所有内容进行控制,则可能生成随机值并将其排序是实现目标的方法。 - freakish像这样:
from random import random
min=0
max=10
oldval=1.
while True:
oldval=oldval*random()
randval=min+(max-min)*oldval
以下是几种替代方案。这将产生接近卡方分布的值,后面选取的值范围比前面的值范围小:
import random
random_range = range(10)
numbers = [random.choice(random_range[:i]) for i in range(10, 0, -1)]
import random
max = 10.0
min = 0.0
desired = 100
step = (max - min) / desired
numbers = [random.random() * (max - (i * step)) for i in range(desired)]
另一种方法是从一个递减的滑动窗口中选择随机值,这样可以提供均匀分布。
import random, numpy
max = 10.0
min = 0.0
desired = 100
step = float(min - max) / desired
window = 1.0
numbers = [x + (random.random() * window) - (window / 2.0) for x in numpy.arange(max, min, step)]
如果需要一个单调递减的数字列表,则设置 window <= step
即可实现。祝好运!
在 @brentlance 的想法基础上,这个方法适用于任何整数范围,包括正数、负数或两者都有:
import random
random_decreasing_integers_from_range = (i for i in xrange(max, min - 1, -1) if random.random() > .5)
如果您想要能够指定输出数量,这里有一个尝试,至少试图保持范围内的分布相对均匀:
import random
def random_decreasing_integers_from_range(min, max, num_outputs):
range_size = abs(max - min)
if range_size < num_outputs:
raise ValueError('Distance from min to max must be equal to or greater than num_outputs.')
output_count = 0
for iteration, value in enumerate(xrange(max, min - 1, -1)):
# if we only have enough values left to satisfy the number requested,
# yield value
if num_outputs - output_count == range_size - iteration + 1:
output_count += 1
yield value
# else yield value randomly, weighted by how far in to the range we are
# and how many values we have left to yield of the total requested
else:
ratio_consumed = float(iteration + 1) / range_size
ratio_yielded = float(output_count) / num_outputs
if random.random() < (1 - ratio_yielded) * ratio_consumed:
output_count += 1
yield value
# if we've yielded the requested number of values, stop
if output_count == num_outputs:
break
这个方法在很大程度上是有效的,但当 num_outputs 不在 range_size 的约 10% 到 25% 之间时,它似乎会出现问题。在下限处,偏向于范围中间确实会显现出来,而在上限处,短路条件开始导致结果真正偏向于范围的下端。
import random
i = 1000000
while i > 0:
i = random.randint(0, i)
print i
这将为您提供在0..1范围内递减的随机数。
import random
def generate():
n = 1.0
while n:
n = random.random() * n
yield n
iterator = generate()
iterator.next()
虽然我不是Python专家,但这是我的基本想法:
a=10000
for i in range(1,50):
b=random.randint(1,a)
print(b)
a=b
1
(并且实际上非常快地呈指数级下降)。因此,分布根本不均匀,对于足够大的范围(1000?),大多数元素将简单地为1。 - freakish