Lot of solutions suggest using xor with right shift, as described here
https://www.geeksforgeeks.org/finding-the-parity-of-a-number-efficiently/
def findParity(x):
x = x ^ (x >> 16);
x = x ^ (x >> 8);
x = x ^ (x >> 4);
x = x ^ (x >> 2);
x = x ^ (x >> 1);
return x & 1;
But they assume 32 or 64 bit or some 2^n bits integer. In python integer could have any number of bits. For instance i = 7, has only 3 bits.
i = 7
print(len(bin(i)) - 2)
Any suggestions on how to calculate parity using xor and right shift for arbitrary number of bits ?
You can use a loop to dynamically change the length of the parity check:
def parity(num):
length = math.ceil(math.log2(math.ceil(math.log2(num)+1)))
for i in range(length-1, -1, -1):
print(2**i)
num^=(num >> (2**i))
return num&1
You will need to use log twice because you first have to find the length of the number then you need log that many operations.
Related
I have generated x = 0 - 2047 in hexadecimal (0 - 7ff).
Then, I tried to shift one bit to right, but I want to keep all the value.
for example, for x = 2047 = h7ff.
I want to shift this value to right. can I set fixed bit length, so that even if I shift, it will not cut the 8?
tried:
x = 2047
hex(x)='0x7ff'
hex(x >> 1)='0x3ff'
expecting:
0x3ff8
If you want to add extra digit only if a bit in the result will be chopped off, you can use a simple modulo. Check if the last bit in the value is a 1, and if it is, multiply the number by 0x10 or decimal 16 to add the extra padding. Then bit shift as normal.
hex((x * 0x10 if x % 2 == 1 else x) >> 1)
adding this to a method for reuse:
def rotate(x):
return (x * 0x10 if x % 2 == 1 else x) >> 1
print(hex(x := 0x7ff))
print(hex(x := rotate(x)))
print(hex(x := rotate(x)))
print(hex(x := rotate(x)))
print(hex(x := rotate(x)))
0x7ff
0x3ff8
0x1ffc
0xffe
0x7ff
I would like to have a bit trick implementation of 64 bit popcount in Python. I tried to copy this code as follows:
def popcount_test(y):
y -= ((y >> 1) & 0x5555555555555555)
y = (y & 0x3333333333333333) + (y >> 2 & 0x3333333333333333)
return ((y + (y >> 4)) & 0xf0f0f0f0f0f0f0f) * 0x101010101010101 >> 56
Unfortunately it is not right. We can see this by doing popcount on the int 1234.
popcount_test(1234)
261
bin(1234).count('1')
5
What is the correct bit trick implement in Python?
Further tests can be carried out with:
import random
num = random.randint(0, 2**64-1)
print(popcount_test(num), bin(num).count('1'))
The problem is that the C version expects the multiply result to only produce the low-order 64 bits, but Python uses extended precision integers so you're getting the whole thing. You can fix it by masking the result to 8 bits after shifting it:
def popcount_test(y):
y -= ((y >> 1) & 0x5555555555555555)
y = (y & 0x3333333333333333) + (y >> 2 & 0x3333333333333333)
return (((y + (y >> 4)) & 0xf0f0f0f0f0f0f0f) * 0x101010101010101 >> 56) & 0xff
This produces the following:
>>> popcount_test(1234)
5
>>>
To make the solution obvious, I'm adding it here, but the credit goes to #TimPeters and #Heap-Overflow
def popcount_test(y):
y -= ((y >> 1) & 0x5555555555555555)
y = (y & 0x3333333333333333) + (y >> 2 & 0x3333333333333333)
return ((((y + (y >> 4)) & 0xf0f0f0f0f0f0f0f) * 0x101010101010101) >> 56) & 0xff
This is how Python does it in Modules/mathmodule.c:
static unsigned long
count_set_bits(unsigned long n)
{
unsigned long count = 0;
while (n != 0) {
++count;
n &= n - 1; /* clear least significant bit */
}
return count;
}
I have an array of (short) data which is shifted 4 to left and it is also a signed number. I need to plot it around zero.
for instance: if the number in the array is 0b0000000011111111 and I shift it to left by 4, I will get 0b000000001111. it is fine.
for instance: if the number in the array is 0b100011111111 and I shift it to left by 4, I will get 0b000010001111. It is fine, but now it is not a negative number.
can someone help ?
You have to write your own implementation of the arithmetic right shift of a 16-bit value, if this is what you need. I suggest you this one, very easy to understand:
def arithmetic_right_shift_on_16_bits(val, n):
# Get the sign bit
s = val & 0x8000
# Perform the shifts, padding with the sign bit
for _ in range(n):
val >>= 1
val |= s
return val
a = arithmetic_right_shift_on_16_bits(0b0000000011111111, 4)
print(bin(a)) # 0b1111
b = arithmetic_right_shift_on_16_bits(0b1000000011111111, 4)
print(bin(b)) # 0b1111100000001111
This does not happen in Python:
>>> bin(0b0000000011111111 >> 4) # 15
'0b1111'
>>> bin(0b100011111111 >> 4) # 143
'0b10001111'
BTW, the number you show as an example of a negative short integer is not one, because you gave only 12 bits. So I will assume that the number of interest is 0b1000000011111111. As Python does not use 2's complement, it is shown as 33023. But you can do the 2's complement by hand: for a short int (16 bits), you just substract 0x10000 to the number.
You can then write:
def short_signed_right_shift(x, i):
if x < 0 or x >= 0x10000: raise ValueError # only accept 16 bits numbers
return x >> i if (x < 0x7FFF) else 0x10000 + ((x - 0x10000) >> i)
You can then use it:
>>> bin(short_signed_right_shift(0b0000000011111111, 4))
'0b1111'
>>> bin(short_signed_right_shift(0b1000000011111111, 4))
'0b1111100000001111'
def different(s):
x = len(s)
for i in range(1, 1 << x):
u.append([s[j] for j in range(x) if (i & (1 << j))])
It takes a list and makes different combinations
(a,b,c) = ((a,b,c),(a,b),(a,c) ...)
But what does the range do? From 1 to what. I don't understand the "<<"
and also, if (i & (1 << j)) what does this do? It checks if i and 2 to the power of j? Doesn't make any sense to me.
The range function returns a list of numbers from zero to the given number minus one. It also has two- and three-argument forms (see the doc for more info):
range(n) == [0, 1, 2, ..., n - 1]
<< is the left-shift operator, and has the effect of multiplying the left hand side by two to the power of the right hand side:
x << n == x * 2**n
Thus the above range function (range(1, 1 << x)) returns [1, 2, 3, ..., 2**x - 1].
In the seconds usage of <<, the left-shift is being used as a bit-mask. It moves the 1-bit into the j-th bit, and performs a bit-wise and with i, so the result will be non-zero (and pass the if test) if and only if the j-th bit of i is set. For example:
j = 4
1 << j = 0b1000 (binary notation)
i = 41 = 0b101001
i & (1 << j) = 0b101001
& 0b001000
= 0b001000 (non-zero, the if-test passes)
i = 38 = 0b100110
i & (1 << j) = 0b100110
& 0b001000
= 0b000000 (zero, the if-test fails)
In short, x & (1 << y) is non-zero iff the y-th bit of x is set.
<< is the binary left shift operator. 1 << x is a way of saying two to the power of x.
Given a Python integer which is within the size of 4 bits, how does one transform it – with bitwise arithmetic instead of string processing – into an integer within the size of 4 bytes, for which each bit in the original corresponds to a byte which is the bit repeated 8 times?
For example: 0b1011 should become 0b11111111000000001111111111111111
With apologies to ncoghlan:
expanded_bits = [
0b00000000000000000000000000000000,
0b00000000000000000000000011111111,
0b00000000000000001111111100000000,
0b00000000000000001111111111111111,
0b00000000111111110000000000000000,
0b00000000111111110000000011111111,
0b00000000111111111111111100000000,
0b00000000111111111111111111111111,
0b11111111000000000000000000000000,
0b11111111000000000000000011111111,
0b11111111000000001111111100000000,
0b11111111000000001111111111111111,
0b11111111111111110000000000000000,
0b11111111111111110000000011111111,
0b11111111111111111111111100000000,
0b11111111111111111111111111111111,
]
Then just index this list with the nibble you want to transform:
>>> bin(expanded_bits[0b1011])
"0b11111111000000001111111111111111"
I'd just do a loop:
x = 0b1011
y = 0
for i in range(4):
if x & (1 << i):
y |= (255 << (i * 8))
print "%x" % y
The following recursive solution uses only addition, left/right shift operators and bitwise & operator with integers:
def xform_rec(n):
if n == 0:
return 0
else:
if 0 == n & 0b1:
return xform_rec(n >> 1) << 8
else:
return 0b11111111 + (xform_rec(n >> 1) << 8)
Or, as a one-liner:
def xform_rec(n):
return 0 if n == 0 else (0 if 0 == n & 0b1 else 0b11111111) + (xform_rec(n >> 1) << 8)
Examples:
>>> print bin(xform_rec(0b1011))
0b11111111000000001111111111111111
>>> print bin(xform_rec(0b0000))
0b0
>>> print bin(xform_rec(0b1111))
0b11111111111111111111111111111111)