4

我想知道是否有办法在一定范围内生成递减数字?我想编程保持输出直到它达到0,并且范围内的最大数字必须是正数。

例如,如果范围是 (0, 100),这可能是一个可能的输出:96 57 43 23 9 0

很抱歉我原来的帖子造成了混乱

4

8 回答 8

18

我会生成一个包含 n 个随机数的列表,然后将它们从高到低排序。

于 2013-01-10T15:08:36.080 回答
6

几乎没有什么需要注意的。从每一步开始的算法X > 0都取一个随机数(0,X)X用它替换是不好的。为什么?因为(假设random行为正常)每一步的期望值都在区间的中间(0,X)。这意味着这些数字的序列有望收敛0(1/2)^N。确实可以很容易地看出,大多数数字都接近0,即使对于巨大的初始值也是如此。这意味着这些数字的分布并不均匀,这是大多数时候所期望的属性。

这是一个主要缺点,即使生成Nth 数字的复杂性是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),这不是那么明显,但确实如此。唯一的缺点是我们必须在开始之前知道要生成多少个数字。

也看看这个线程:

在没有排序的情况下生成排序的随机整数?上)

可能有用。

于 2013-01-10T23:42:35.917 回答
2

喜欢:

from random import random
min=0
max=10
oldval=1.

while True:
  oldval=oldval*random()
  randval=min+(max-min)*oldval
于 2013-01-10T15:12:05.393 回答
2

这里有一些选择。这应该产生接近卡方分布的值,后面的值从比早期值更小的范围中选择:

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将提供一个。祝你好运!

于 2013-01-10T15:12:43.840 回答
1

基于@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% 之间时,它似乎会崩溃。在下限处,确实显示出偏向范围的中间,而在上限处,短路条件开始导致结果真正偏向范围的下限。

于 2013-01-10T15:40:58.857 回答
1

谢谢大家的回答。但是我找到了解决我自己问题的方法,我认为这很简单,我想与大家分享。

import random
i = 1000000  

while i > 0:
    i = random.randint(0, i)
    print i
于 2013-01-13T20:42:04.857 回答
0

不是python专家......但这是我的基本想法:

a=10000
for i in range(1,50):
   b=random.randint(1,a)
   print(b)
   a=b
于 2013-01-10T15:46:44.587 回答
0

这将使您在 0..1 范围内减少随机数。

import random
def generate():
    n = 1.0
    while n:
        n = random.random() * n
        yield n
iterator = generate()
iterator.next()

请注意,由于浮点数的精度有限,数字不可避免地会达到 0,因此该函数会在一段时间后停止生成数字。

于 2013-01-10T15:21:04.760 回答