5 & 0xFFFFFFFF # 5
-5 & 0xFFFFFFFF # 4294967291
In Python, why bitwise AND a negative number with 0xFFFFFFFF will give a different result? Since 0 & 1 = 0 and 1 & 1 = 1, should bitwise AND a number with 0xFFFFFFFF (11111111111111111111111111111111) keep every digit what it was?
To give some more illustration, in python, to get the bit representation of -5 you apply two's complement rule, that is: start from 5, flipped bits, add 1
-5 -> 0000....0000000101 (5 in binary) -> 1111....1111111010 (flipped) -> 1111....1111111011 (+1)
When you & it with 0xFF you are doing this:
1111....1111111011
& 0000....0011111111
= 000000000011111111 = +255
I've used 0xFF but that does not matter since as #Tom Karzes mentioned,
Python integers have no fixed width, so negative numbers are treated
as having an infinite number of leading 1s.
and positive numbers have an infinite number of leadin 0s.
Related
I have two numbers:
num1 = 1
num2 = 1
And then someone applied a secret operation on them:
mask = 2**8 -1
secret = (num1 << 8) | (num2 & mask)
>>> 257
How can I do the opposite of the secret operation? to get from 257 to 1 1
this is a standard way of encoding 2 small integers into a larger one
its 16bits of data representing 2 8 bit integers
to get the first one (upper 8 bits) back you shift it the other way
256 >> 8
to get the lower 8 bits just and it with the original mask
256 & (2**8-1)
as mentioned in the comments most ints are int32 (32 bits, not 8) and you likely cannot recover num2 if its value was greater than 255, because 8 bits can only represent 0-255
as an aside I imagine most people would use (1<<8)-1 instead of 2**8-1
I'm a little confused by the ~ operator. Code goes below:
a = 1
~a #-2
b = 15
~b #-16
How does ~ do work?
I thought, ~a would be something like:
0001 = a
1110 = ~a
why not?
You are exactly right. It's an artifact of two's complement integer representation.
In 16 bits, 1 is represented as 0000 0000 0000 0001. Inverted, you get 1111 1111 1111 1110, which is -2. Similarly, 15 is 0000 0000 0000 1111. Inverted, you get 1111 1111 1111 0000, which is -16.
In general, ~n = -n - 1
The '~' operator is defined as:
"The bit-wise inversion of x is defined as -(x+1). It only applies to integral numbers."Python Doc - 5.5
The important part of this sentence is that this is related to 'integral numbers' (also called integers). Your example represents a 4 bit number.
'0001' = 1
The integer range of a 4 bit number is '-8..0..7'. On the other hand you could use 'unsigned integers', that do not include negative number and the range for your 4 bit number would be '0..15'.
Since Python operates on integers the behavior you described is expected. Integers are represented using two's complement. In case of a 4 bit number this looks like the following.
7 = '0111'
0 = '0000'
-1 = '1111'
-8 = '1000'
Python uses 32bit for integer representation in case you have a 32-bit OS. You can check the largest integer with:
sys.maxint # (2^31)-1 for my system
In case you would like an unsigned integer returned for you 4 bit number you have to mask.
'0001' = a # unsigned '1' / integer '1'
'1110' = ~a # unsigned '14' / integer -2
(~a & 0xF) # returns 14
If you want to get an unsigned 8 bit number range (0..255) instead just use:
(~a & 0xFF) # returns 254
It looks like I found simpler solution that does what is desired:
uint8: x ^ 0xFF
uint16: x ^ 0xFFFF
uint32: x ^ 0xFFFFFFFF
uint64: x ^ 0xFFFFFFFFFFFFFFFF
You could also use unsigned ints (for example from the numpy package) to achieve the expected behaviour.
>>> import numpy as np
>>> bin( ~ np.uint8(1))
'0b11111110'
The problem is that the number represented by the result of applying ~ is not well defined as it depends on the number of bits used to represent the original value. For instance:
5 = 101
~5 = 010 = 2
5 = 0101
~5 = 1010 = 10
5 = 00101
~5 = 11010 = 26
However, the two's complement of ~5 is the same in all cases:
two_complement(~101) = 2^3 - 2 = 6
two_complement(~0101) = 2^4 - 10 = 6
two_complement(~00101) = 2^5 - 26 = 6
And given that the two's complement is used to represent negative values, it makes sense to consider ~5 as the negative value, -6, of its complement.
So, more formally, to arrive at this result we have:
flipped zeros and ones (that's equivalent to taking the ones' complement)
taken two's complement
applied negative sign
and if x is a n-digit number:
~x = - two_complement(one_complement(x)) = - two_complement(2^n - 1 - x) = - (2^n - (2^n - 1 - x)) = - (x + 1)
How do I create 1's complement and 2's complement code for negative numbers in Python?
I had some problems with inversion and leading zero (one) in process.
I tried to use res = bin(~int(bin(numb), 2)), but it doesn't work.
I need result like:
Input: -123
Direct code: 11111011
Ones' complement code: 10000100
Two’s complement code: 10000101
The operator - is two's complement and ~ is one's complement. The representation of both are negative numbers, because python integers has infinite digits. Positive means infinite 0s, negative infinite 1s. For display, you need to truncate the numbers to a finite amount of digits.
>>> '{:08b}'.format(-123 & 0xff)
'10000101'
>>> '{:08b}'.format(~123 & 0xff)
'10000100'
>
You can do something like this to compute the 2's compliement:
def extra(x, bits = 64):
mask = (1 << bits) - 1
if x < 0:
x = ((abs(x) ^ mask) + 1)
return bin(x)[2:]
and like this for 1's complement:
def reverse(y, bits = 64):
mask = (1 << bits) - 1
if y < 0:
y = (abs(y) ^ mask)
return bin(y)[2:]
Given an n-bit integer, I want to find the set of n-bit integers which are related to my original integer by the interchange of a single 1 by a single 0 where the interchanged 1 and 0 must be adjacent
So what I want is to find some function such that for example, if I gave it the binary 1011 (11 in base 10) it returns 0111 and 1101 (7 and 13 in base 10)
ie. so this would look like:
>>> bit_hop(11, n=4)
[7, 13]
It's important that this function knows how many bits the number is because my other constraint is that I need this to have periodic boundary conditions such that for example 0111 would return not only 1011 but also 1110, ie. the edges of the binary number should be adjacent.
Also, as said, only one swapping should be allowed per hop. This means that bit_hop(1010) should return [1100, 0011, 1001, 0110]
Does anyone have any ideas on how one might go about doing this? I know that this should involve some clever usage of the >>, << and ^ operations but I'm having trouble seeing the synthesis.
To do this directly in binary, you have to notice a couple of things about the algorithm. First it always deals with adjacent bits, except for looping around from the first bit to the last. Second those bits must be different, if they're the same swapping them wouldn't do anything.
This code walks a 2-bit mask around the value and tests to see if the bits are different, then uses exclusive-or to swap them.
def bit_hop(x, n):
for i in range(n-1):
mask = 3 << i
if x & mask != 0 and x & mask != mask:
yield x ^ mask
mask = (1 << (n-1)) | 1
if x & mask != 0 and x & mask != mask:
yield x ^ mask
Below a and b (hex), representing two's complement signed binary numbers.
For example:
a = 0x17c7cc6e
b = 0xc158a854
Now I want to know the signed representation of a & b in base 10. Sorry I'm a low level programmer and new to python; feel very stupid for asking this. I don't care about additional library's but the answer should be simple and straight forward. Background: a & b are extracted data from a UDP packet. I have no control over the format. So please don't give me an answer that would assume I can change the format of those varibles before hand.
I have converted a & b into the following with this:
aBinary = bin(int(a, 16))[2:].zfill(32) => 00010111110001111100110001101110 => 398969966
bBinary = bin(int(b, 16))[2:].zfill(32) => 11000001010110001010100001010100 => -1051154348
I was trying to do something like this (doesn't work):
if aBinary[1:2] == 1:
aBinary = ~aBinary + int(1, 2)
What is the proper way to do this in python?
why not using ctypes ?
>>> import ctypes
>>> a = 0x17c7cc6e
>>> ctypes.c_int32(a).value
398969966
>>> b = 0xc158a854
>>> ctypes.c_int32(b).value
-1051154348
A nice way to do this in Python is using bitwise operations. For example, for 32-bit values:
def s32(value):
return -(value & 0x80000000) | (value & 0x7fffffff)
Applying this to your values:
>>> s32(a)
398969966
>>> s32(b)
-1051154348
What this function does is sign-extend the value so it's correctly interpreted with the right sign and value.
Python is a bit tricky in that it uses arbitrary precision integers, so negative numbers are treated as if there were an infinite series of leading 1 bits. For example:
>>> bin(-42 & 0xff)
'0b11010110'
>>> bin(-42 & 0xffff)
'0b1111111111010110'
>>> bin(-42 & 0xffffffff)
'0b11111111111111111111111111010110'
>>> import numpy
>>> numpy.int32(0xc158a854)
-1051154348
You'll have to know at least the width of your data. For instance, 0xc158a854 has 8 hexadecimal digits so it must be at least 32 bits wide; it appears to be an unsigned 32 bit value. We can process it using some bitwise operations:
In [232]: b = 0xc158a854
In [233]: if b >= 1<<31: b -= 1<<32
In [234]: b
Out[234]: -1051154348L
The L here marks that Python 2 has switched to processing the value as a long; it's usually not important, but in this case indicates that I've been working with values outside the common int range for this installation. The tool to extract data from binary structures such as UDP packets is struct.unpack; if you just tell it that your value is signed in the first place, it will produce the correct value:
In [240]: s = '\xc1\x58\xa8\x54'
In [241]: import struct
In [242]: struct.unpack('>i', s)
Out[242]: (-1051154348,)
That assumes two's complement representation; one's complement (such as the checksum used in UDP), sign and magnitude, or IEEE 754 floating point are some less common encodings for numbers.
Another modern solution:
>>> b = 0xc158a854
>>> int.from_bytes(bytes.fromhex(hex(b)[2:]), byteorder='big', signed=True)
-1051154348
2^31 = 0x80000000 (sign bit, which in two's compliment represents -2^31)
2^31-1 = 0x7fffffff (all the positive bits)
and hence (n & 0x7fffffff) - (n & 0x80000000) will apply the sign correctly
you could even do, n - ((n & 0x80000000)<<1) to subtract the msb value twice
or finally there's, (n & 0x7fffffff) | -(n & 0x80000000) to just merge the negative bit, not subtract
def signedHex(n): return (n & 0x7fffffff) | -(n & 0x80000000)
signedHex = lambda n: (n & 0x7fffffff) | -(n & 0x80000000)
value=input("enter hexa decimal value for getting compliment values:=")
highest_value="F"*len(value)
resulting_decimal=int(highest_value,16)-int(value,16)
ones_compliment=hex(resulting_decimal)
twos_compliment=hex(r+1)
print(f'ones compliment={ones_compliment}\n twos complimet={twos_compliment}')