The answer这个标记重复的问题是错误的,不能满足我的需要。
我的代码旨在从一系列数字中计算哈希值。
以矩阵的形式理解结构更容易。如果我从29开始有16个数字,结构将是:(开始= 29,长度= 4)
29,30,31,32,
33,34,35,36,
37,38,39,40,
41,42,43,44
给定算法指定散列将是以粗体给出的数字的XOR:
29,30,31,32, //,
33,34,35, //,36,
37,38, //,39,40,
41, //,42,43,41
哈希= 29^30^31^32^33^34^35^37^38^39
= 54
我的代码是:
def answer(start, length):
val=0
c=0
for i in range(length):
for j in range(length):
if j < length-i:
val^=start+c
c+=1
return val
计算像answer(2000000000,10**4)
这样的大值所需的时间太多了。
约束:
目前计算测试参数(我不知道)给我一个超时错误。
如何为更大的值提高代码的速度?
答案 0 :(得分:4)
这是一个已修复的版本,还有一个l
测试,以验证它是否提供与天真算法相同的结果。
assert
在def f(a):
return (a, 1, a + 1, 0)[a % 4]
def getXor(a, b):
return f(b) ^ f(a-1)
def gen_nums(start, length):
l = length
ans = 0
while l > 0:
l = l - 1
ans ^= getXor(start, start + l)
start += length
return ans
def answer(start, length):
c = val = 0
for i in xrange(length):
for j in xrange(length - i):
n = start + c + j
#print '%d,' % n,
val ^= n
#print
c += length
return val
for start in xrange(50):
for length in xrange(100):
a = answer(start, length)
b = gen_nums(start, length)
assert a == b, (start, length, a, b)
和start
的范围内,length
比gen_nums
快5倍,但我们可以再次快两倍(即大致)通过消除这些函数调用,速度是answer
的10倍:
answer
正如Mirek Opoka在评论中提到的那样,def gen_nums(start, length):
ans = 0
for l in xrange(length - 1, -1, -1):
b = start + l
ans ^= (b, 1, b + 1, 0)[b % 4] ^ (0, start - 1, 1, start, 0)[start % 4]
start += length
return ans
等同于% 4
,并且它更快,因为按位算术比执行整数除法和丢弃商更快。所以我们可以用
& 3
答案 1 :(得分:1)
看起来您可以替换内部循环,如果使用:
for j in range(length - i)
val^=start+c
c+=1
c+=i
当我变大时,这应该可以节省一些时间
我担心我现在无法对此进行测试,抱歉!
答案 2 :(得分:1)
我担心,如果您在answer(2000000000,10**4)
中输入,您将永远无法“及时”完成。
通过改进内循环,每次更新c
变量并使用xrange
代替range
,您可以获得非常显着的加速,如下所示:
def answer(start, length):
val=0
c=0
for i in range(length):
for j in range(length):
if j < length-i:
val^=start+c
c+=1
return val
def answer_fast(start, length):
val = 0
c = 0
for i in xrange(length):
for j in xrange(length - i):
if j < length - i:
val ^= start + c + j
c += length
return val
# print answer(10, 20000)
print answer_fast(10, 20000)
分析器显示answer_fast
的速度大约是其两倍:
> python -m cProfile script.py
366359392
20004 function calls in 46.696 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 46.696 46.696 script.py:1(<module>)
1 44.357 44.357 46.696 46.696 script.py:1(answer)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
20001 2.339 0.000 2.339 0.000 {range}
> python -m cProfile script.py
366359392
3 function calls in 26.274 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 26.274 26.274 script.py:1(<module>)
1 26.274 26.274 26.274 26.274 script.py:12(answer_fast)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
但是如果你想要主要的加速(大订单)你应该考虑在Cython中重写你的功能。
以下是它的“cythonized”版本:
def answer(int start, int length):
cdef int val = 0, c = 0, i, j
for i in xrange(length):
for j in xrange(length - i):
if j < length - i:
val ^= start + c + j
c += length
return val
使用与上述输入参数相同的输入参数,所需的时间不到200毫秒20秒,这是100倍的加速。
> ipython
In [1]: import pyximport; pyximport.install()
Out[1]: (None, <pyximport.pyximport.PyxImporter at 0x7f3fed983150>)
In [2]: import script2
In [3]: timeit script2.answer(10, 20000)
10 loops, best of 3: 188 ms per loop
使用输入参数,需要58ms:
In [5]: timeit script2.answer(2000000000,10**4)
10 loops, best of 3: 58.2 ms per loop