e.g. when 1010 is the given number, i want it to output:
0010
1110
1000
1011
I have tried to do it without imports to challenge myself. I've tried to put each number in a list and flip each digit accordingly. I get stuck when it doesn't update the first number. It outputs:
0010
0110
0000
0011
CodePudding user response:
Binary numbers represent a number as a sum of powers of 2 written from right to left (just like decimal numbers represent a number as a sum of powers of 10 written from right to left).
If you get your value as a string ('1010'
) you can turn it into an integer, if you get it as an integer (0b1010
) you of course wouldn't need to:
value = '1010'
x = int(value, 2) # interpret string as binary
a = 1
while a < x:
print(x ^ a, '{0:04b}'.format(x ^ a))
a = a * 2
This line:
print(x ^ a, '{0:04b}'.format(x ^ a))
It prints x ^ a
, which is the logical XOR of x
and a
, meaning that it will have a 1
wherever x
and a
are different, and 0
elsewhere. Since a
will be a power of 2, it will only have 1 bit set to 1, and so it will flip just that bit.
The second part starts with '{0:04b}'
, which will format the same value as binary, using 4 positions.
If you don't like that it's reversed, you'd need to know where to start (i.e. the greatest power of 2 that still fits into the number), but that is a given if you know the length of the string you want:
value = '1010'
x = int(value, 2) # interpret string as binary
for a in range(len(value)-1, -1, -1):
print(x ^ 2**a, '{0:04b}'.format(x ^ 2**a))
Or, as a one-liner:
value = '1010'
print(' '.join(f'{int(value, 2) ^ 2**a:04b}' for a in range(len(value)-1, -1, -1)))
These two examples loop through powers of 2, starting at the greatest power of two that fits inside the starting value, down to 2^0
(1
) and perform the same trick as before.
The one-liner then also puts the results together with spaces, as in your example.
Outputs:
2 0010
14 1110
8 1000
11 1011
0010 1110 1000 1011
CodePudding user response:
The simple solution is to convert string to list, replace the required index and convert it back to the string.
s = "1010"
res = []
for i in range(0, len(s)):
t = list(s)
t[i] = '1' if t[i] == '0' else '0'
res.append(''.join(t))
print(res) #['0010', '1110', '1000', '1011']
CodePudding user response:
N = 345678909876543223456
for i in range(N.bit_length()):
print(N^(1<<i))
You can use simple bitwise operators:
^
is Xor, basically bit^1
flips the bit
<<
is a left shift, basically 1<<N
appends N zero in front of the bit -> 1000...Ntimes
CodePudding user response:
Since Grismar brought up efficiency, here's a benchmark on a longer string ('1010' * 3000
) with two more solutions:
210 ms Grismar1
345 ms Grismar2
2043 ms Akshay
52 ms Kelly1
13 ms Kelly2
For better comparison I made all solutions generators that yield the strings.
Full code (Try it online!):
def Kelly1(s):
for i, c in enumerate(s):
yield s[:i] ('1' if c == '0' else '0') s[i 1:]
def Kelly2(s):
bs = bytearray(s, 'ascii')
for i, b in enumerate(bs):
bs[i] ^= 1
yield bs.decode()
bs[i] = b
def Grismar1(value):
x = int(value, 2) # interpret string as binary
a = 1
while a <= x:
yield'{0:04b}'.format(x ^ a)
a = a * 2
def Grismar2(value):
x = int(value, 2) # interpret string as binary
for a in range(len(value)-1, -1, -1):
yield'{0:04b}'.format(x ^ 2**a)
def Akshay(s):
for i in range(0, len(s)):
t = list(s)
t[i] = '1' if t[i] == '0' else '0'
yield ''.join(t)
funcs = Grismar1, Grismar2, Akshay, Kelly1, Kelly2
for f in funcs:
print(*f('1010'), f.__name__)
from timeit import repeat
from collections import deque
for f in funcs * 2:
value = '1010' * 3000
t = min(repeat(lambda: deque(f(value), 0), number=1))
print('M ms ' % (t * 1e3), f.__name__)