Convert decimal number to binary number and change one index - python

I am looking for the fastest solution of the following problem:
My function takes a decimal number dec and then converts it to a binary number bin of length l. Afterwards I change the value at the i'th index of the binary number and convert the result back to a decimal number. Currently I implemented this in the following way:
def new_dec_function(dec, i, l):
bin = list(map(int, numpy.binary_repr(dec, width=l)))
bin[i] = 1 - bin[i]
new_dec = 0
for bit in bin:
new_dec = (new_dec << 1) | bit
return new_dec
Do you know if this can be improved?

The 'decimal' number you speak of is already stored in binary representation in your computer, so all you have to do is flip the i'th bit of the number. This can be easily accomplished with the binary xor operator ^
def new_dec_function(dec, i):
return dec ^ (1 << i)
>>> new_dec_function(5, 1)
7
>>> new_dec_function(5, 0)
4

Related

Reverse bits program logic not clear

I was asked to write a program of reversing bits of a given 32 bits unsigned integer.
For example, if the input is 43261596, the output should be 964176192 (binary of input is 00000010100101000001111010011100, and after reversing output becomes 00111001011110000010100101000000 whose decimal equivalent is 964176192).
I wrote the following program:
class Solution:
def reverseBits(self, n: int) -> int:
binary = ""
for i in range(32):
binary = binary + str(n%2)
n = n//2
return int(binary,2)
Upon submission, this answer was received with an alternative solution that was 'claimed to be more time ans space efficient'. Here's the alternative one:
class Solution:
def reverseBits(self, n: int) -> int:
if (n == 0):
return 0
result = 0
for i in range(32):
result <<= 1
if ((n & 1) == 1):
result +=1
n >>= 1
return result
The logic they provided was left/right shifting of bits.
I am totally clueless as to how does bit shifting to the left/right help in reversing the bits of a decimal integer. To further clarify, I myself wrote this snippet:
a = 9
print(a>>1,a<<1)
The outputs were 4 and 18 respectively(integer halved and doubled).
But how does this concept contribute to revrsing bits of an integer? And also why is this considered more time and space efficient than my solution? Please help.
The bit shifting is similar to your string concatenation, binary = binary + str(n%2) effectively shifts the already existing characters to the left by one position (similar to result <<= 1). Since for the bit shift approach, this will add a 0 at the end, they need to optionally increase the value by 1 if the last binary digit of the current n is 1 (result += 1). Then n >>= 1 does the same as n //= 2.
The second approach basically requires an additional 32 bit for the result (at least theoretically), while the string approach will end up with a 32-character string which uses about 32 bytes. Also integer operations will likely be faster than string operations.

Converting either a Decimal or Binary value to Binary signed 2's complement in Python

I am having trouble in achieving either of the following in Python:
Convert a Decimal value to Binary signed 2's complement. Examples:
40975 = 00000000000000001010000000001111
275 = 0000000100010011
Convert a Binary value to Binary signed 2's complement. Examples:
1010000000001111 = 00000000000000001010000000001111
100010011 = 0000000100010011
Does anyone know of the easiest way of achieving this in Python?
I found the solution, below is the explanation of what I did.
I needed to do the following:
1) Determine the length of the binary value:
2) Determine the smallest power of 2 greater than that the length output, then add 0's to the left of the binary output until the length matches that returned smallest power of 2 value.
A few of the solutions for the above can be found on this excellent thread Find the smallest power of 2 greater than n in Python. Here are the three of the functions I've tried:
len_1 = 16
len_2 = 9
def next_power_of_2_ver_1(x):
return 1 if x == 0 else 2**(x).bit_length()
Output:
32
16
def next_power_of_2_ver_2(x):
return 1 if x == 0 else 2**math.ceil(math.log2(x + 1))
Output:
32
16
def next_power_of_2_ver_3(x):
return 1<<(x).bit_length()
Output:
32
16
I have settled on the following solution:
def next_power_of_2_ver_3(x):
return 1<<(x).bit_length()
Though this is a part of a larger code that I have, the operation that achieves what I need is as follows:
import math
# this function returns the smallest power of 2 greater than the binary output length so that we may get Binary signed 2's complement
def next_power_of_2(x):
return 1<<(x).bit_length()
decimal_value = "40975"
# convert the decimal value to binary format and remove the '0b' prefix
binary_value = bin(int(decimal_value))[2:]
Output: 1010000000001111
# determine the length of the binary value
binary_value_len = len(binary_value)
Output: 16
# use function 'next_power_of_2' to return the smallest power of 2 greater than the binary output length
power_of_2_binary_value_len = next_power_of_2(binary_value_len)
Output: 32
# determine the amount of '0's we need to add to the binary result
calc_leading_0 = power_of_2_binary_value_len - binary_value_len
Output: 16
# adds the leading zeros thus completing the binary signed 2's complement formula
binary_signed_2s_binary_value = (binary_value).zfill(binary_value_len + calc_leading_0)
Output: 00000000000000001010000000001111

What is good way to negate an integer in binary operation in python?

Based on what I've read about the binary representation of integers, the first bit is for sign (positive or negative).
Let's say we have an integer x = 5 and sys.getsizeof(x) returns 28 (that is binary representation in 28 bit).
For now I am trying to flip the first bit to 1 by using x|=(1<<27)but it returns 134217733.
I was just wondering whether it needs to be some negative number? (not -5)
Is there anything wrong with what I am doing?
You can't switch a Python int from positive to negative the way you're trying to, by just flipping a bit in its representation. You're assuming it's stored in a fixed-length two's complement representation. But integers in Python 3 are not fixed-length bit strings, and they are not stored in a two's complement representation. Instead, they are stored as variable-length strings of 30- or 15-bit "digits", with the sign stored separately (like a signed-magnitude representation). So the "lowest-level" way to negate a Python int is not with bit operations, but with the unary - operator, which will switch its sign. (See the end of this answer for details from the Python 3 source.)
(I should also mention that sys.getsizeof() does not tell you the number of bits in your int. It gives you the number of bytes of memory that the integer object is using. This is also not the number of bytes of the actual stored number; most of those bytes are for other things.)
You can still play around with two's complement representations in Python, by emulating a fixed-length bit string using a positive int. First, choose the length you want, for example 6 bits. (You could just as easily choose larger numbers like 28 or 594.) We can define some helpful constants and functions:
BIT_LEN = 6
NUM_INTS = 1 << BIT_LEN # 0b1000000
BIT_MASK = NUM_INTS - 1 # 0b111111
HIGH_BIT = 1 << (BIT_LEN - 1) # 0b100000
def to2c(num):
"""Returns the two's complement representation for a signed integer."""
return num & BIT_MASK
def from2c(bits):
"""Returns the signed integer for a two's complement representation."""
bits &= BIT_MASK
if bits & HIGH_BIT:
return bits - NUM_INTS
Now we can do something like you were trying to:
>>> x = to2c(2)
>>> x |= 1 << 5
>>> bin(x)
'0b100010'
>>> from2c(x)
-30
Which shows that turning on the high bit for the number 2 in a 6-bit two's complement representation turns the number into -30. This makes sense, because 26-1 = 32, so the lowest integer in this representation is -32. And -32 + 2 = -30.
If you're interested in the details of how Python 3 stores integers, you can look through Objects/longobject.c in the source. In particular, looking at the function _PyLong_Negate():
/* If a freshly-allocated int is already shared, it must
be a small integer, so negating it must go to PyLong_FromLong */
Py_LOCAL_INLINE(void)
_PyLong_Negate(PyLongObject **x_p)
{
PyLongObject *x;
x = (PyLongObject *)*x_p;
if (Py_REFCNT(x) == 1) {
Py_SIZE(x) = -Py_SIZE(x);
return;
}
*x_p = (PyLongObject *)PyLong_FromLong(-MEDIUM_VALUE(x));
Py_DECREF(x);
}
you can see that all it does in the normal case is negate the Py_SIZE() value of the integer object. Py_SIZE() is simply a reference to the ob_size field of the integer object. When this value is 0, the integer is 0. Otherwise, its sign is the sign of the integer, and its absolute value is the number of 30- or 15-bit digits in the array that holds the integer's absolute value.
Negative number representations in python :
Depending on how many binary digit you want, subtract from a number (2n):
>>> bin((1 << 8) - 1)
'0b11111111'
>>> bin((1 << 16) - 1)
'0b1111111111111111'
>>> bin((1 << 32) - 1)
'0b11111111111111111111111111111111'
Function to generate two's compliment(negative number):
def to_twoscomplement(bits, value):
if value < 0:
value = ( 1<<bits ) + value
formatstring = '{:0%ib}' % bits
return formatstring.format(value)
Output:
>>> to_twoscomplement(16, 3)
'0000000000000011'
>>> to_twoscomplement(16, -3)
'1111111111111101'
Refer : two's complement of numbers in python

two's complement of numbers in python

I am writing code that will have negative and positive numbers all 16 bits long with the MSB being the sign aka two's complement. This means the smallest number I can have is -32768 which is 1000 0000 0000 0000 in two's complement form. The largest number I can have is 32767 which is 0111 1111 1111 1111.
The issue I am having is python is representing the negative numbers with the same binary notation as positive numbers just putting a minus sign out the front i.e. -16384 is displayed as -0100 0000 0000 0000 what I want to be displayed for a number like -16384 is 1100 0000 0000 0000.
I am not quite sure how this can be coded. This is the code i have. Essentially if the number is between 180 and 359 its going to be negative. I need to display this as a twos compliment value. I dont have any code on how to display it because i really have no idea how to do it.
def calculatebearingActive(i):
numTracks = trackQty_Active
bearing = (((i)*360.0)/numTracks)
if 0< bearing <=179:
FC = (bearing/360.0)
FC_scaled = FC/(2**(-16))
return int(FC_scaled)
elif 180<= bearing <=359:
FC = -1*(360-bearing)/(360.0)
FC_scaled = FC/(2**(-16))
return int(FC_scaled)
elif bearing ==360:
FC = 0
return FC
If you're doing something like
format(num, '016b')
to convert your numbers to a two's complement string representation, you'll want to actually take the two's complement of a negative number before stringifying it:
format(num if num >= 0 else (1 << 16) + num, '016b')
or take it mod 65536:
format(num % (1 << 16), '016b')
The two's complement of a value is the one's complement plus one.
You can write your own conversion function based on that:
def to_binary(value):
result = ''
if value < 0:
result = '-'
value = ~value + 1
result += bin(value)
return result
The result looks like this:
>>> to_binary(10)
'0b1010'
>>> to_binary(-10)
'-0b1010'
Edit: To display the bits without the minus in front you can use this function:
def to_twoscomplement(bits, value):
if value < 0:
value = ( 1<<bits ) + value
formatstring = '{:0%ib}' % bits
return formatstring.format(value)
>>> to_twoscomplement(16, 3)
'0000000000000011'
>>> to_twoscomplement(16, -3)
'1111111111111101'
If you actually want to store the numbers using 16 bits, you can use struct.
import struct
>>> struct.pack('h', 32767)
'\xff\x7f'
>>> struct.pack('h', -32767)
'\x01\x80'
You can unpack using unpack
>>> a = struct.pack('h', 32767)
>>> struct.unpack('H', a)
32767
Python can hold unlimited integer values, the bit representation will adopt to hold any number you put. So such technical details as two complement does not make sense in this context. In C 'b1111111111111111' means -1 for int16 and 65535 for uint16 or int32. In python it is always is 65535 as the int will adopt to hold such values.
I think this is why they opted to add - in front of negative numbers regardless of string representation (binary, oct, hex, decimal ...).
If you wish to replicate the C behaviour and get the negative represented in two complement form you have the following options:
1 int > uint > bin using numpy
The most straight forward way is to dump the value as signed limited int and read it as unsigned.
If you have access to numpy the code is pretty easy to read:
>>> bin(np.int16(-30).astype(np.uint16))
'0b1111111111100010'
>>> bin(np.int16(-1).astype(np.uint16))
'0b1111111111111111'
>>> bin(np.int16(-2).astype(np.uint16))
'0b1111111111111110'
>>> bin(np.int16(-16).astype(np.uint16))
'0b1111111111110000'
2 int > uint > bin using struct
You can do the similar think with struct but it is slightly harder to understand
>>> bin(struct.unpack('>H', struct.pack('>h', 30))[0])
'0b1111111111100010'
>>> bin(struct.unpack('>H', struct.pack('>h', -1))[0])
'0b1111111111111111'
>>> bin(struct.unpack('>H', struct.pack('>h', -2))[0])
'0b1111111111111110'
>>> bin(struct.unpack('>H', struct.pack('>h', -16))[0])
'0b1111111111110000'
Note: h is signed and H is unsigned int 16, and '>' stands for bigendian it comes handy if you want to read bytes directly without converting them back to int
3. int using struct, then read byte by byte and convert to bin
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -1<<15))
'1000000000000000'
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -1))
'1111111111111111'
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -2))
'1111111111111110'
>>> ''.join(f'{byte:08b}' for byte in struct.pack('>h', -16))
'1111111111110000'
Note this has some quirks, as you need to remember to enforce the byte binary representation to be 8 digits long with '08'.
3 Directly from math,
Lastly you can go check what wikipedia says about 2 complement representation and get it implemented directly from the math formula Two complement > Subtraction from 2N
>>> bin(2**16 -16)
'0b1111111111110000'
>>> bin(2**16 -3)
'0b1111111111111101'
This looks super simple but it is hard to understand if you are not versed in the way 2 complement representation works.
Since you haven't given any code examples, I can't be sure what's going on. Based on the numbers in your example, I don't think you're using bin(yourint) because you're output doesn't contain 0b. Maybe you're already slicing that off in your examples.
If you are storing your binary data as strings, you could do something like:
def handle_negatives(binary_string):
If binary_string < 0:
binary_string = '1' + str(binary_string)[1:]
Return binary_string
Here are some caveats in printing complements(1s and 2s) in binary form, in python:
UNSIGNED RANGE: 0 to (2^k)-1 for k bit number
ex: 0 to (2^32)-1 numbers
ex: 0 to 7 for 3 bit unsigned numbers (count = 8)
SIGNED RANGE: -2^(k-1) to +2^(k-1)-1 for 1+k bit number (k-1 is for dividing current range k into two equal half)
ex: -2^31 to +(2^31)-1 numbers
ex -8 to +7 for 1+3 bit signed numbers (count = 8)
bin(int)->str converts an integer to binary string
CAVEAT: 1. Since in python there is no limit to length of integer
for ~x or !x (1s_complement/not/negate) we can't determine how many bits after MSB needs to be 1
so python just prints out unsigned value of target negative number in binary format with a
'-' sign in the beginning
ex: for x = b'01010'(10) we get ~x = -0b'1011' (-11)
but we should be getting -16+5 = -11
(-b'10000'+b'00101') = -b'10101' (-11 signed) or (21 unsigned)
to get real binary value after negation(or 1s complement) one could simulate it
NOTE: 2^0 is always 1, so (2**0 == 1) in python
NOTE: (1 << k) is always 2^k (left shift is 2 raised to the power k)
ex: bin((1 << k)-1 - x) which is ((2^k)-1)-x (1s complement)
ex: bin((1 << k)-1 - x) + 1 which is (2^k)-x (2s complement)
2. Same goes for reverse parsing of signed binary string to int:
ex: int("-0b'0101'", 2) gives -5 but instead it actually is -11 assuming -0b represents all bits
from MSB till current to be like 1111......0101 which is actually -16+5 = -11
BUT due to PYTHON's limitation of representing signed binary values we need to adhere to
current way of parsing considering unsigned binary strings with sign in front for -ve numbers
# NOTE: how the significant prefix zeros doesn't matter in both +ve and -ve cases
# Byte type inputs
x = b'+1010' # valid +ve number byte string
x = b'1010' # valid +ve number byte string
x = b'-1010' # valid -ve number byte string
x = b'+01010' # valid +ve number byte string
x = b'01010' # valid +ve number byte string
x = b'-01010' # valid -ve number byte string
int(b'101') # interprets as base 10 for each digit
int(b'101', 2) # interprets as base 2 for each digit
int(b'101', 8) # interprets as base 8 for each digit
int(b'101', 10) # interprets as base 10 for each digit
int(b'101', 16) # interprets as base 16 for each digit
# String type inputs
x = '+1010' # valid +ve number string
x = '1010' # valid +ve number string
x = '-1010' # valid -ve number string
x = '+01010' # valid +ve number string
x = '01010' # valid +ve number string
x = '-01010' # valid -ve number string
int('101') # interprets as base 10 for each digit
int('101', 2) # interprets as base 2 for each digit
int('101', 8) # interprets as base 8 for each digit
int('101', 10) # interprets as base 10 for each digit
int('101', 16) # interprets as base 16 for each digit
# print(bin(int(x, 2)), int(x,2), ~int(x, 2), bin(~int(x,2)), "-"+bin((1<<k)-1 - int(x,2)))
k = 5 # no of bits
assert 2**0 == 1 # (2^0 is always 1)
_2k = (1 << k) # (2^k == left shift (2^0 or 1) by k times == multiply 2 by k times)
x = '01010' # valid +ve number string
x = int(x,2)
print("input:", x) # supposed to be 1s complement of binStr but due to python's limitation,
# we consider it -(unsigned binStr)
_1s = '-'+bin((_2k-1)-x)
print("1s complement(negate/not): ", _1s, ~x)
_2s = '-'+bin(_2k-x)
print("2s complement(1s +1): ", _2s, ~x+1)
output:
k = 5 (5 bit representation)
input: 10
1s complement(negate/not): -0b10101 -11
2s complement(1s +1): -0b10110 -10
k=32 (32 bit representation)
input: 10
1s complement(negate/not): -0b11111111111111111111111111110101 -11
2s complement(1s +1): -0b11111111111111111111111111110110 -10

Python: Choose number of bits to represent binary number

I am curious as to how I can change the number of bits to represent a binary number.
For example, say I want express decimal 1 to binary. I use:
bin(1) and get 0b1.
How can I get the return to say 0b01 or 0b001 or 0b0001 etc?
Use the Format String Syntax:
>>> format(1, '#04b')
'0b01'
>>> format(1, '#05b')
'0b001'
>>> format(1, '#06b')
'0b0001'
You can use str.zfill to pad the binary part:
def padded_bin(i, width):
s = bin(i)
return s[:2] + s[2:].zfill(width)
I don't believe there's a builtin way to do this. However, since bin just returns a string, you could write a wrapper function which modifies the string to have the right number of bits:
def binbits(x, n):
"""Return binary representation of x with at least n bits"""
bits = bin(x).split('b')[1]
if len(bits) < n:
return '0b' + '0' * (n - len(bits)) + bits
#

Categories

Resources