The task of determining if more than one bit has changed can be done by:
- Calculating the
XOR of value 1 and value 2.
- If the
XOR of the values is not a power of two, more than one bit has been changed, e.g. (x & (x - 1)), where the XOR value is x.
For example:
for idx, (b1, b2) in enumerate(zip(data, data[1:])):
a = int(''.join(map(str, (*b1[0], b1[1]))), 2)
b = int(''.join(map(str, (*b2[0], b2[1]))), 2)
if (a ^ b) & ((a ^ b) - 1):
print(f'Change in index {idx} and {idx+1}', b1, b2)
gives the following output:
Change in index 0 and 1 [(0, 0, 1), 1] [(0, 1, 0), 1]
Change in index 2 and 3 [(0, 1, 0), 1] [(0, 1, 1), 0]
Change in index 4 and 5 [(0, 1, 1), 0] [(1, 0, 0), 0]
Change in index 8 and 9 [(1, 0, 1), 0] [(1, 1, 0), 0]
Comments:
This operation was made tricky by the fact of the first set of bits are nested within a tuple, and the final bit is not. This is the reason for the 'ridiculous' derivation of the a and b variables, to convert the nested bits into a base-2 integer value.
Edit:
Added additional logic to address the comment:
If I want to see if only one bit changed what I should do?
The logic is very similar, however has a key difference as the result of a single change and a non-change (using x & (x-1)) have the same value: 0. Therefore we must:
- Test a change has occurred.
- Verify the change has only affected a single bit.
For example:
for idx, (b1, b2) in enumerate(zip(data, data[1:])):
a = int(''.join(map(str, (*b1[0], b1[1]))), 2)
b = int(''.join(map(str, (*b2[0], b2[1]))), 2)
xor = a ^ b
if (xor) and not (xor & (xor - 1)):
print(f'Change in index {idx} and {idx+1}', b1, b2)
The statement if (xor) and not (xor & (xor - 1)) tests there was a change (xor) (using truth value testing) and the change affects only a single bit (not (xor & (xor - 1))).
Output:
Change in index 6 and 7 [(1, 0, 0), 0] [(1, 0, 1), 0]