The answer of the question this is marked duplicate of is wrong and does not satisfy my needs.
My code aims to calculate a hash from a seri
There is a bug in the accepted answer to Python fast XOR over range algorithm: decrementing l
needs to be done before the XOR calculation. Here's a repaired version, along with an assert
test to verify that it gives the same result as the naive algorithm.
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)
Over those ranges of start
and length
, gen_nums
is about 5 times faster than answer
, but we can make it roughly twice as fast again (i.e., roughly 10 times as fast as answer
) by eliminating those function calls:
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] ^ (start - 1, 1, start, 0)[start % 4]
start += length
return ans
As Mirek Opoka mentions in the comments, % 4
is equivalent to & 3
, and it's faster because bitwise arithmetic is faster than performing integer division and throwing away the quotient. So we can replace the core step with
ans ^= (b, 1, b + 1, 0)[b & 3] ^ (start - 1, 1, start, 0)[start & 3]