Given any number n, and three operations on n:
I want to find the minimum n
I like the idea by squeamish ossifrage of greedily looking (for the case of odd numbers) whether n + 1 or n - 1 looks more promising, but think deciding what looks more promising can be done a bit better than looking at the total number of set bits.
For a number x
,
bin(x)[:: -1].index('1')
indicates the number of least-significant 0s until the first 1. The idea, then, is to see whether this number is higher for n + 1 or n - 1, and choose the higher of the two (many consecutive least-significant 0s indicate more consecutive halving).
This leads to
def min_steps_back(n):
count_to_1 = lambda x: bin(x)[:: -1].index('1')
if n in [0, 1]:
return 1 - n
if n % 2 == 0:
return 1 + min_steps_back(n / 2)
return 1 + (min_steps_back(n + 1) if count_to_1(n + 1) > count_to_1(n - 1) else min_steps_back(n - 1))
To compare the two, I ran
num = 10000
ms, msb = 0., 0.
for i in range(1000):
n = random.randint(1, 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999)
ms += min_steps(n)
msb += min_steps_back(n)
print ms / num, msb / num
Which outputs
57.4797 56.5844
showing that, on average, this does use fewer operations (albeit not by that much).