如何在Python中生成指数增长范围

20

我想使用指数增长的值来测试一些代码的性能。这样,随着数字大小增加一个额外的数字,增量就会乘以10。目前我是这样做的,但看起来有点hacky。是否有改进的建议,而不引入非标准库?

numbers_size = 100
increment = 100
numbers_range = 1000000000
while numbers_size < numbers_range:
    t = time.time()
    test( numbers_size )
    taken_t = time.time() - t
    print numbers_size, test, taken_t

    increment = 10 ** (len(str(numbers_size))-1)
    numbers_size += increment

你已经得到了答案,但能否请问原因? - Jon Clements
为了给我即将举行的关于Python性能技巧的演讲展示搜索列表和字典的区别。 - Martlark
9个回答

23

如果你认为NumPy是标准之一 ;),那么你可以使用numpy.logspace,因为这就是它的作用...(注意:100=10^2,1000000000=10^9)

for n in numpy.logspace(2,9,num=9-2, endpoint=False):
    test(n)

例子2(注意:100=10^2,1000000000=10^9,如果要前进10倍,则需要9-2+1个点...):

In[14]: np.logspace(2,9,num=9-2+1,base=10,dtype='int')
Out[14]: 
array([       100,       1000,      10000,     100000,    1000000,
         10000000,  100000000, 1000000000])

例子3:

In[10]: np.logspace(2,9,dtype='int')
Out[10]: 
array([       100,        138,        193,        268,        372,
              517,        719,       1000,       1389,       1930,
             2682,       3727,       5179,       7196,      10000,
            13894,      19306,      26826,      37275,      51794,
            71968,     100000,     138949,     193069,     268269,
           372759,     517947,     719685,    1000000,    1389495,
          1930697,    2682695,    3727593,    5179474,    7196856,
         10000000,   13894954,   19306977,   26826957,   37275937,
         51794746,   71968567,  100000000,  138949549,  193069772,
        268269579,  372759372,  517947467,  719685673, 1000000000])

在您的情况下,我们使用endpoint=False,因为您不希望建立终点...(例如np.logspace(2,9,num=9-2, endpoint=False)


20

为什么不呢

for exponent in range(2, 10):
    test(10 ** exponent)

如果我理解你的意图正确。


14
为了生成与你代码相同的数字:
numbers_sizes = (i*10**exp for exp in range(2, 9) for i in range(1, 10))
for n in numbers_sizes:
    test(n)

5
最简单的方法是使用指数的线性序列:
for e in range(1, 90):
    i = int(10**(e/10.0))
    test(i)

你可以将这个序列提取为自己的生成器:
def exponent_range(max, nsteps):
    max_e = math.log10(max)
    for e in xrange(1, nsteps+1):
        yield int(10**(e*max_e/nsteps))

for i in exponent_range(10**9, nsteps=100):
    test(i)

5

我喜欢Ned Batcheldor的答案,但我会让它更普遍一些:

def exp_range(start, end, mul):
    while start < end:
        yield start
        start *= mul

那么你的代码将变成:

for sz in exp_range(100, 1000000000, 10):
    t = time.time()
    test(sz)
    print sz, test(sz), time.time()-t

1

OP写道:“有没有不引入非标准库的改进建议?”

为了完整起见,这里提供一种生成指数范围的方法 - 每个元素都比前一个元素大一个固定因子:

from math import exp
from math import log

def frange(start, stop, numelements):
    """range function for floats"""
    incr = (stop - start) / numelements
    return (start + x * incr for x in range(numelements))

def exprange(start, stop, numelements):
    """exponential range - each element is a fixed factor bigger than the previous"""
    return (exp(x) for x in frange(log(start), log(stop), numelements))

测试:

print(", ".join("%.3f" % x for x in exprange(3,81,6)))

输出:

3.000, 5.196, 9.000, 15.588, 27.000, 46.765

0

假如你不想使用任何库或额外的函数定义:

for n in [10**m for m in range(d)]:
    print(n)

这个列表推导式可以实现你想要的功能。
如果需要,将 d 转换为字符串并计算其长度。
d = len(str(numbers_range))

0
使用生成器表达式:
max_exponent = 100
for i in (10**n for n in xrange(1, max_exponent)):
    test(i)

-2

没有仔细阅读问题不知道如何做的例子

for i in xrange(100, 1000000000, 100):
    # timer
    test(i)
    # whatever

这就是最简单的方法了...根据需要调整xrange即可


1
这个被踩了(虽然不是我),可能是因为你的范围是线性的,而不是指数的。 - msw
@msw 说得好,感谢你。我会坚持我的错误(正确地阅读问题不是如何解决它),这样可以作为社区的参考资料。 - Jon Clements
2
我连续给你一些我认为值得的旧回答点赞,原因有两个:首先,我讨厌那些不愿意解释的“路过”踩票者;其次,我欣赏新手的贡献。至于为什么OP要用这种非常困难的方式来做,我和你一样感到困惑,但我不指望我们会在这方面得到回应。 - msw
@msw 非常感谢 - 当然这并不是必要的 :) 我之所以发现 Stack Overflow,是因为我想在 pandas 上提问,除了这里,我找不到任何邮件列表/联系方式。然后,我有点上瘾了,分享我所知道的东西总是很愉快的事情,学习我不知道的东西也很棒 :) 如果我做错了什么,没关系,我会接受批评 - 我不会把它当作个人攻击...但还是谢谢 :) - Jon Clements

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接