Question

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
Was it helpful?

Solution

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')

OTHER TIPS

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

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top