Creating a bit mask with BigInts - python

Is there a more efficient way of performing the following calculation? It works fine, but something tells me that x &= (1 << 8) - 1 ^ 1 << 3 can be written to avoid some calculations and increase speed.
def unset_mask(width, index):
return (1 << width) - 1 ^ 1 << index
x = 0b11111111
x &= unset_mask(8, 3)
assert x == 0b11110111

Actually, you don't need to state the width. Bigints behave the right way when you do this:
>>> bin(255 & ~(1 << 3))
'0b11110111'
>>> bin(65535 & ~(1 << 3))
'0b1111111111110111'
>>> bin(75557863725914323419135 & ~(1 << 3))
'0b1111111111111111111111111111111111111111111111111111111111111111111111110111'
It's because negative numbers have an "infinite" string of ones preceding them. So when you complement a positive number (which starts with an "infinte" string of zeros), you get a negative number (-(x + 1) to be exact). Just don't trust the bin representation of negative numbers; it doesn't reflect the actual bits in memory.
So you would rewrite unset_mask like so:
def unset_mask(index):
return ~(1 << index)
x = 0b11111111
x &= unset_mask(3)
print x == 0b11110111 # prints True

You can use this to clear a bit in x:
x &= ~(1 << index)

This will unset the bit:
x ^= 1 << 3 & x
In a function:
def unset_bit(x, n):
return 1 << n & x ^ x

Related

Circular shift of a bit in python (equivalent of Fortran's ISHFTC)

I want to achieve the equivalent of the ISHFTC function in Fortran using python.
What is the best way to do this?
For example,
x = '0100110'
s = int(x, 2)
s_shifted = ISHFTC(s,1,7) #shifts to left by 1
#binary representation of s_shifted should be 1001100
My attempt based on Circular shift in c
def ISHFTC(n, d,N):
return (n << d)|(n >> (N - d))
However, this does not do what I want. Example,
ISHFTC(57,1,6) #57 is '111001'
gives 115 which is '1110011' whereas I want '110011'
Your attempted solution does not work because Python has unlimited size integers.
It works in C (for specific values of N, depending on the type used, typically something like 8 or 32), because the bits that are shifted out to the left are automatically truncated.
You need to do this explicitly in Python to get the same behaviour. Truncating a value to the lowest N bits can be done be using % (1 << N) (the remainder of dividing by 2N).
Example: ISHFTC(57, 1, 6)
We want to keep the 6 bits inside |......| and truncate all bits to the left. The bits to the right are truncated automatically, because the these are already the 6 least significant bits.
n |111001|
a = n << d 1|110010|
m = (1 << N) 1|000000|
b = a % m 0|110010|
c = n >> (N - d) |000001|(11001)
result = b | c |110011|
Resulting code:
def ISHFTC(n, d, N):
return ((n << d) % (1 << N)) | (n >> (N - d))
# ^^^^^^ a
# ^^^^^^ m
# ^^^^^^^^^^^^^^^^^ b
# ^^^^^^^^^^^^ c
>>> ISHFTC(57, 1, 6)
51
>>> bin(_)
'0b110011'

Python3 logical left shift

By default the 'left shift' operation in Python ( << ) acts as an arithmetic shift and appends a 0 bit to the end of the bits representing the int.
For example:
100 << 1 returns 200
In the binary representation we can see that 100 = 0b1100100 (7 bits) and 100 << 1 = 0b11001000 (8 bits)
In Python 3 what is the best way to perform a logical left shift where the number of bits stays constant, but the values are shifted to the left one?
For example:
100 << 1 would return 72
In the binary representation 100 = 0b1100100 and 100 << 1 = 0b1001000
We've kept the same 7 bits, but just shifted to the left one and appended a 0 to the end.
You can use int.bitlength to get the number of bits required to represent the number, then and the result of the shift with (1 << bitlength) - 1 to restrict the result to that many bits:
def lls_const_bits(n):
return (n << 1) & ((1 << n.bit_length()) - 1)
print(lls_const_bits(100))
Output:
72
If you want to restrict the output to a fixed number of bits b, you would need to mask with (1 << b) - 1:
def lls_const_bits(n, b):
return (n << 1) & ((1 << b) - 1)
print(lls_const_bits(100, 7))
Output:
72

What's the best way to modify a bitwise Karatsuba-Algorithm to work with negative numbers?

I wrote this bitwise Karatsuba multiplication algorithm. It does not use strings or math.pow. It's just divide-and-conquer-recursion, bitwise operations and addition:
def karatsuba(x,y):
n = max(x.bit_length(), y.bit_length())
if n < 2:
return x&y
# split in O(1)
n = (n + 1) >> 1
b = x >> n;
a = x - (b << n);
d = y >> n;
c = y - (d << n);
ac = karatsuba(a, c);
bd = karatsuba(b, d);
abcd = karatsuba(a+b, c+d);
return ac + ((abcd - ac - bd) << n) + (bd << (n << 1));
print(karatsuba(23,24))
print(karatsuba(-29,31))
# 552
# 381
It works absolutly fine with positive numbers, but obviously -29*31 is not equal 381.
What's the easiest way to fix the problem?
My first idea was to make the number positive with (~(-29)+1) = 29, store wheather it was negative or not in a boolean and handle that boolean in my return statement, but is there a better (maybe bitwise) solution?
Thanks in advance
The issue is with your exit case, in particular x&y returns the wrong value for negative numbers:
-1 & 1 == 1 # Needs to return -1
So you can fix this with testing for it or or just returning:
if n < 2:
return x*y
E.g.:
In []:
print(karatsuba(-29,31))
Out[]:
-899

Please help me understand a bit shift operation

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.

Transform bits into byte series

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)

Categories