简体   繁体   中英

(~) Why are my bits not flipping?

I thought that ~ should make 1s into 0s and vice-versa. I used it in my code, yet I'm getting -2s and -1s.

def inverse_graph(graph):
    # for each vertex in graph
    revg = list(graph)
    for i, line in enumerate(revg):
        for j, vertex in enumerate(line):
            if  i != j:
                # flip value
                graph[i][j] = ~ graph[i][j]
                #if vertex == 0:
                #    graph[i][j] = 1;
                #else:
                #    graph[i][j] = 0;
    return revg



def test():
        g1 = [[0, 1, 1, 0],
              [1, 0, 0, 1],
              [1, 0, 0, 1],
              [0, 1, 1, 0]]
        assert inverse_graph(g1) == [[0, 0, 0, 1],
                                     [0, 0, 1, 0],
                                     [0, 1, 0, 0],
                                     [1, 0, 0, 0]]
        g2 = [[0, 1, 1, 1],
              [1, 0, 1, 1],
              [1, 1, 0, 1],
              [1, 1, 1, 0]]
        assert inverse_graph(g2) == [[0, 0, 0, 0],
                                     [0, 0, 0, 0],
                                     [0, 0, 0, 0],
                                     [0, 0, 0, 0]]

.............................................................................................................................................................................................................

Actually, -2 is ~1. Two's complement , remember?

>>> bin(1)
'0b1'
>>> bin(~1)
'-0b10'

The thing is: you're not using bits, but integers. So either you want to revert to using eg Booleans (which read less nicely) or you want to use some expression like 0 if x else 1 to flip your elements.

Tip: you can use comprehensions to write this more elegantly:

>>> flipped = lambda graph: [ [0 if x else 1  for x in row]  for row in graph]
>>> flipped( [ [1, 0], [0, 1] ] )
[[0, 1], [1, 0]]

With numpy it is much easier.

>>> import numpy as np
>>> g1=np.array([[0, 1, 1, 0],
...              [1, 0, 0, 1],
...              [1, 0, 0, 1],
...              [0, 1, 1, 0]])
>>> g2=1-g1
>>> g2
array([[1, 0, 0, 1],
       [0, 1, 1, 0],
       [0, 1, 1, 0],
       [1, 0, 0, 1]])

~ will work with Boolean datatype:

>>> g1=np.array([[0, 1, 1, 0],   # 1 represents True and 0 represents False
...              [1, 0, 0, 1],
...              [1, 0, 0, 1],
...              [0, 1, 1, 0]], dtype=bool)
>>> ~g1
array([[ True, False, False,  True],
       [False,  True,  True, False],
       [False,  True,  True, False],
       [ True, False, False,  True]], dtype=bool)

If you want complement(~) in 0s and 1s rather than in True False, this will do the trick:

>>> ~g1+0
array([[1, 0, 0, 1],
       [0, 1, 1, 0],
       [0, 1, 1, 0],
       [1, 0, 0, 1]])

As xtofl has pointed out, Python's integers use Two's complement representation. This means that the bitwise inverse of 0 is not 1 , but an infinitely long sequence of binary 1 s, which is interpreted as -1 . The inverse of 1 is not 0 , but an infinite number of ones, followed by one zero (which is -2 ).

Of course, the number of bits stored for each integer is not infinite. Python will normally use the C integer type long that your system defines (it is usually 32 or maybe 64 bits long), but operations that would overflow will instead automatically switch to Python's own arbitrary precision long type if the value is too large to fit (this conversion is handled transparently within the int type in Python 3).

Anyway, an alternative solution is to use:

graph[i][j] = 1 - graph[i][j]

Or, if you don't mind the values becoming instances of the int subtype bool :

graph[i][j] = not graph[i][j]

Python's bool values are still usable as numbers ( False works just like 0 and True is just like 1 ). The only real difference is that they'll print out with text instead of digits.

While the others are right, an easier way of saying 0 if x else 1 is not x or maybe int(not x) .

not x returns False if x != 0 and True otherwise. False and True are bool s, which is a subclass of int . They can readily be used in a calculation, but for the case you prefer to get proper 0 s and 1 s, or if you need them for indexing a dict , int(not x) might be better.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM