'Get the closest higher value from a sequence
I have a sequence like: 4, 8, 16, 32, 64, 128, 256, 512
now I have a number
a = 5
then
b = 8
means b is the closest higher digit according to a from the sequence.
Now a = x then b = ?
Solution 1:[1]
I offer two solutions. The first is probably the most obvious and intuitive. The second is more advanced but more efficient.
Simple and intuitive
Here is a simple intuitive approach. The following function returns the closest number greater than or equal to the argument num in the sequence 4, 8, 16, 32, 64, .... The function first assigns n to 4. Then, so long as n is strictly less than the argument num, n is assigned the next value in the sequence and the comparison is made again. Once n is greater than or equal to num, we return n.
def seq_1(num):
"""Returns the closest number greater than or equal to num in the
sequence 4, 8, 16, 32, 64, ...
"""
n = 4
while (n < num):
n *= 2
return n
More efficient, but more advanced
A less intuitive approach but more efficient is obtained by first recognizing that the sequence is defined by
a_0 = 4;a_n = 2 * a_(n-1)fornin{1, 2, 3, ...}.
Notice how a_(n-1) = 2 * a_(n-2). Substituting this into a_n = 2 * a_(n-1), we obtain a_n = (2 ** 2) * a_(n-2). More generally, through repeated substitutions, we obtain a_n = (2 ** n) * a_(0) or a_n = (2 ** n) * 4 or
a_n = (2 ** (n + 2))for n in {0, 1, 2, 3, ...}
So the first element a_0 is 2 ** 2 = 4, the second element a_1 is 2 ** 3 = 8, the third is 2 ** 4 = 16 and so on.
This suggests the solution:
def seq_2(num):
"""Returns the closest number greater than or equal to num in the
sequence 4, 8, 16, 32, 64, ...
"""
if num < 4:
return 4
return 1 << (num - 1).bit_length()
- if
numis less than4we return4. 1 << (num - 1).bit_length()evaluates to the closest power of 2 greater than or equal tonum.
This requires the following knowledge:
2is10in binary,2 ** 2is100in binary,2 ** 3is1000in binary, ...,2 ** nin binary is1followed bynzeros.bit_length()is a method defined for Pythonints that "[r]eturn[s] the number of bits necessary to represent an integer in binary" (docs).i << jshiftsileft byjbits. For example
In [1]: bin(1)
Out[1]: '0b1' # 2 to the power of 0.
In [2]: bin(1 << 5)
Out[2]: '0b100000' # 2 to the power of 5.
Timings
# seq_1(420_000)
657 ns ± 0.55 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
# seq_2(420_000)
116 ns ± 0.416 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
Solution 2:[2]
Providing that your sequence is in ascending sorted order then:
seq = [4,8,16,32,64,128,256,512]
def get_next_highest(seq, a):
b = None
for i in range(len(seq)-1, -1, -1):
if seq[i] <= a:
break
b = seq[i]
return b
print(get_next_highest(seq, 5))
Solution 3:[3]
If you have a sorted sequence you can use bisect from Pythons standard library.
import bisect
data = [4, 8, 16, 32, 64, 128, 256, 512]
a = 5
index = bisect.bisect(data, a)
b = data[index]
You will have to add a boundary check if you expect a to have a value larger than the last element of the list.
This code demonstrates how it works with random values.
import bisect
import random
def get_next_highest(data, value):
try:
return data[bisect.bisect(data, value)]
except IndexError:
return None
def main():
data = sorted([random.randint(1, 100) for _ in range(10)])
a = 50
b = get_next_highest(data, a)
print(data, a, b)
if __name__ == '__main__':
main()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Albert Winestein |
| Solution 3 |
