Convert binary string into two's complement - python

For our homework assignemnt, we are asked to take in an integer and return the two's complement of it.
Currently, I am able to convert the integer into a binary string. From there, I know I need to invert the 0's and 1's and add 1 to the new string, but I do not know how to do that.
Could someone help me with that please?
def numToBinary(n):
'''Returns the string with the binary representation of non-negative integer n.'''
result = ''
for x in range(8):
r = n % 2
n = n // 2
result += str(r)
result = result[::-1]
return result
def NumToTc(n):
'''Returns the string with the binary representation of non-negative integer n.'''
binary = numToBinary(n)
# stops working here
invert = binary
i = 0
for digit in range(len(binary)):
if digit == '0':
invert[i] = '1'
else:
invert[i] = '0'
i += 1
return invert
Note: This is an intro level course, so we are mainly stuck to using loops and recursion. We cannot really use any fancy formatting of strings, built-in functions, etc. beyond the basics.

I was able to reach my solution by doing the following:
def numToBinary(n):
'''Returns the string with the binary representation of non-negative integer n.'''
result = ''
for x in range(8):
r = n % 2
n = n // 2
result += str(r)
result = result[::-1]
return result
def NumToTc(n):
'''Returns the string with the binary representation of non-negative integer n.'''
binary = numToBinary(n)
for digit in binary:
if int(digit) < 0:
binary = (1 << 8) + n
return binary

Related

positive and negative fraction to binary conversion

I am trying to convert positive and negative fractions to binary, I found the following approach online (https://www.geeksforgeeks.org/convert-decimal-fraction-binary-number/) to convert positive fractions to binary and tried to extend it to support the negative fractions.
I am trying to do the 2's complement on the fractional part. Any help is much appreciated.
# decimal to binary number
# Function to convert decimal to binary
# upto k-precision after decimal point
def decimalToBinary(num, k_prec) :
binary = ""
# Fetch the integral part of
# decimal number
Integral = int(num)
# Fetch the fractional part
# decimal number
fractional = num - Integral
# Conversion of integral part to
# binary equivalent
while (Integral) :
rem = Integral % 2
# Append 0 in binary
binary += str(rem);
Integral //= 2
# Reverse string to get original
# binary equivalent
binary = binary[ : : -1]
# Append point before conversion
# of fractional part
binary += '.'
# Conversion of fractional part
# to binary equivalent
while (k_prec) :
# Find next bit in fraction
fractional *= 2
fract_bit = int(fractional)
if (fract_bit == 1) :
fractional -= fract_bit
binary += '1'
else :
binary += '0'
k_prec -= 1
if (num < 0): # if negative numbers do the two's complement
binary = ~binary # struck here.
else:
binary = binary
return binary
# Driver code
if __name__ == "__main__" :
num_list=[1, 0, 0.924, -0.383]
for i in num_list:
print(i, decimalToBinary(i,8))
macky#test:~/test$ python frac_to_binary.py
(1, '1.00000000')
(0, '.00000000')
(0.924, '.11101100')
Traceback (most recent call last):
File "frac_to_binary.py", line 63, in <module>
print(i, decimalToBinary(i,8))
File "frac_to_binary.py", line 54, in decimalToBinary
binary = ~binary
TypeError: bad operand type for unary ~: 'str'
There are actually a few ways to display binary numbers as negatives. The important thing to remember is to watch your bit size; set your bit size larger than the max value that you want to convert, or weird things may happen:
bits = 4 for numbers <= 7 (0111)
bits = 5 for numbers <= 15 (01111)
bits = 8 for numbers <= 127 (01111111)
Another thing to remember is that you have to convert the whole binary representation, not each part.
I modified your function to display four types of representations: Signed, Sign Magnitude, One's Complement, and Two's Complement:
NOTE - Tested on CentOS 7.9, using Python 2.7, and on Ubuntu 20.04, using Python 3.8
"""Program to convert rational numbers to signed and unsigned binary representations
Signed: Add a sign (0001 = 1, -0001 = -1)
Sign Magnitude: The sign is the most significant bit (0001 = 1, 1001 = -1)
One's Complement: Flip all the bits to their opposite value (0001 = 1, 1110 = -1)
Two's Complement: Flip all the bits, then add 1 to the least significant bit (0001 = 1, 1111 = -1)
Signed and decimal values checked at
https://www.rapidtables.com/convert/number/binary-to-decimal.html
Complements checked at https://planetcalc.com/747/
Warning: Set your bit size larger than the max value that you want to convert:
bits = 4 for numbers <= 7 (0111)
bits = 5 for numbers <= 15 (01111)
...
bits = 8 for numbers <= 127 (01111111)
"""
def decimal_to_binary(num, bits):
"""Function to convert rational numbers to binary representations
:param float num: The decimal to convert to binary
:param int bits: The bit size; see warning in the module docstring
:return: A formatted string with Signed, Sign Mag, One's Comp, and Two's Comp representations
:rtype: str
"""
# Ensure the number is a float
num *= 1.0
# Separate the number's components
whole_part = int(str(num).split(".")[0])
decimal_part = float("." + str(num).split(".")[1])
# Convert the whole part to binary
if whole_part >= 0:
whole_binary = format(whole_part, "0{0}b".format(bits))
else:
# Remove the sign
whole_binary = format(whole_part * -1, "0{0}b".format(bits))
# Convert the decimal part to binary
k_prec = bits
if decimal_part == 0:
decimal_binary = format(0, "0{0}b".format(k_prec))
else:
db_list = []
while k_prec > 0:
decimal_part *= 2
db_list.append(int(decimal_part))
decimal_part -= int(decimal_part)
k_prec -= 1
decimal_binary = ''.join(str(d) for d in db_list)
# Put the binary representations back together and sign (for Signed and Sign Magnitude)
binary = whole_binary + "." + decimal_binary
mag_binary = "0" + binary[1:] if num >= 0 else "1" + binary[1:]
signed_binary = binary if num >= 0 else "-" + binary
if num >= 0:
ones_binary = "n/a"
twos_binary = ""
else:
# Create an unsigned binary representation (for Complements)
raw_binary = whole_binary + decimal_binary
ones_binary = ""
# Flip bits; as chepner says, ~ doesn't work on strings
for c in raw_binary:
ones_binary += '1' if c == '0' else '0'
# Add 1 to the least significant digit
twos_binary = bin(int(ones_binary, 2) + 1)
# Format for display
ones_binary = ones_binary.replace("0b", "")
ones_binary = ones_binary[:bits] + "." + ones_binary[bits:]
twos_binary = twos_binary.replace("0b", "")
twos_binary = twos_binary[:bits] + "." + twos_binary[bits:]
return "{0:>8}\t{1:>10}\t{2}\t{3}\t{4}".format(
num, signed_binary, mag_binary, ones_binary, twos_binary)
def main():
# I am using 4 bits for readability, so I am keeping the numbers below 7
num_list = [1, 0, 0.924, -0.383, -0.5, -1, ]
print("Original\t Signed\t Sign Mag\tOne's Comp\tTwo's Comp")
for i in num_list:
print(decimal_to_binary(i, 4))
if __name__ == "__main__":
main()
Output:
Original Signed Sign Mag One's Comp Two's Comp
1.0 0001.0000 0001.0000 n/a
0.0 0000.0000 0000.0000 n/a
0.924 0000.1110 0000.1110 n/a
-0.383 -0000.0110 1000.0110 1111.1001 1111.1010
-0.5 -0000.1000 1000.1000 1111.0111 1111.1000
-1.0 -0001.0000 1001.0000 1110.1111 1111.0000
I tested the results using RapidTables' Binary to Decimal converter and PlanetCalc's One's complement, and two's complement binary codes calculator.
If I had more time, I would break this up into separate functions and streamline a few things, but I leave that up to you. Good luck with your code!

Multiplication of binaries through repeated addition

Let's say we're trying to multiply 10011 and 1101 (or in arithmetic terms, 19 x 13). We all know that this is the same as adding 10011 to itself 13 times or vice versa. Apparently, I've found a code at https://www.w3resource.com/python-exercises/challenges/1/python-challenges-1-exercise-31.php which provided a way on how to add two binary numbers. My question is, in general, if we multiply two binary numbers A and B, how are we going to iterate A to add itself B times? Obviously, in order to do that we have to convert B to decimal/integer first.
def add_binary_nums(x, y):
max_len = max(len(x), len(y))
x = x.zfill(max_len)
y = y.zfill(max_len)
result = ''
carry = 0
for i in range(max_len-1, -1, -1):
r = carry
r += 1 if x[i] == '1' else 0
r += 1 if y[i] == '1' else 0
result = ('1' if r % 2 == 1 else '0') + result
carry = 0 if r < 2 else 1
if carry !=0 : result = '1' + result
return result.zfill(max_len)
print(add_binary_nums('11', '1'))
You can count up to a number by starting at 0 and adding 1 until you are done. Since you already have defined a binary add, you only need to add the loop:
def binary_range(stop: str):
"""Count `stop` times"""
current = '0'
while stop != current:
yield current
current = add_binary_nums(current, '1')
This is enough to do something "n times". You can now do "a * b" as "add a to itself b times":
def binary_mul(a: str, b: str):
"""Multiplay the binary ``a`` by the binary ``b``"""
result = '0'
for _ in binary_range(b):
result = add_binary_nums(result, a)
return result
If you don't care about building a binary calculator, use Python to convert binary to integers or vice versa. int(bin_string, 2) converts a string such as "01101" to the appropriate integer, and bin(integer) converts it back to "0b01101".
For example, a binary multiplication that takes and returns strings looks like this:
def binary_mul(a: str, b: str):
return bin(int(a, 2) * int(b, 2))[:2]

How to write float -> string and get the same digits as "%.f"

Today I wrote a naive function that converts a float to a string by repeatedly modding by 10 and dividing by 10.
def to_string(x):
r = ""
while x >= 1.0:
r = str(int(x%10)) + r
x /= 10.0
return r
I then tested my function against Python's built-in capability to convert a float to a string. Not too surprisingly, my function differs on large numbers.
>>> to_string(1e30)
'1000000000000000424684240284426'
>>> "%.f"%1e30
'1000000000000000019884624838656'
So, my question is: what computation do I have to do to get the digits that Python gets?
Here is a very simple solution. It is not intended to be efficient or to handle any values other than positive integers.
#!/usr/bin/python
import math
# This code represents a hexadecimal number using a list in which each item
# is a single hexadecimal digit (an integer from 0 to 15).
# Divide the base-16 digit-list in x by digit d. This uses grade-school
# division, for a single-digit divisor. It returns the quotient in a new
# digit-list and the remainder as a plain integer.
def Divide(x, d):
# If the first digit is smaller than d, start an empty quotient with
# a remainder being carried.
if x[0] < d:
q = []
r = x[0]
# Otherwise, start the quotient by dividing the first digit by d.
else:
q = [x[0] / d]
r = x[0] % d
# For the remaining digits, multiply the remainder by the base and
# add the new digit. Then divide by d, calculating a new digit of the
# quotient and a new remainder to carry.
for i in x[1:]:
r = r*16 + i
q.append(r/d)
r = r % d
return (q, r)
# Convert a positive integer floating-point value to decimal and print it.
def to_string(x):
# Convert input to base 16. This has no rounding errors since the
# floating-point format uses base two, and 16 is a power of two.
t= []
while 0 < x:
# Use remainder modulo 16 to calculate the next digit, then insert it.
t.insert(0, int(x % 16))
# Remove the digit from x.
x = math.floor(x/16)
# Start an empty output string.
output = ""
# Divide the number by 10 until it is zero (is an empty digit list).
# Each time we divide, the remainder is a new digit of the answer.
while t != []:
(t, r) = Divide(t, 10)
output = str(r) + output
print output
to_string(1e30)

How to convert between floats and decimal twos complement numbers in Python?

I want to convert decimal float numbers in python into twos complement decimal binary numbers. For example 1.5 in twos complement decimal 2.6 (8 bits) would be 0b011000.
Is there a module that can do this for me?
What you're describing has nothing at all to do with decimal. You want to convert a float to a fixed-point binary representation. To do this, you would multiply the float by a scale factor, cast it to an integer, and use Python's built-in string formatting tools to get the string representation:
def float_to_binary(float_):
# Turns the provided floating-point number into a fixed-point
# binary representation with 2 bits for the integer component and
# 6 bits for the fractional component.
temp = float_ * 2**6 # Scale the number up.
temp = int(temp) # Turn it into an integer.
# If you want -1 to display as 0b11000000, include this part:
# if temp < 0:
# temp += 2**8
# The 0 means "pad the number with zeros".
# The 8 means to pad to a width of 8 characters.
# The b means to use binary.
return '{:08b}'.format(temp)
Well, I couldnt find anything so I wrote some code and tested it.Should work...
def floatToTwosComplementDecimal(intBits,decBits,number):
if decBits == 0:
mx = pow(2,intBits-1) - 1 # maximum number
else:
mx = pow(2,intBits-1) - pow(2,-1*decBits) # maximum number
mn = -1*pow(2,intBits-1) # minimum number
if number > mx:
print "number:" + str(number) + " has been truncated to: " + str(mx)
number = mx
elif number < mn:
print "number:" + str(number) + " has been truncated to: " + str(mn)
number = mn
n = []
m = 0
if number < 0:
n.append(1)
m = -1*pow(2,intBits-1)
else:
n.append(0)
m = 0
for i in reversed(range(intBits-1)):
m1 = m + pow(2,i)
if number < m1:
n.append(0)
else:
n.append(1)
m = m1
for i in range(1,decBits+1):
m1 = m + pow(2,-1*i)
if number < m1:
n.append(0)
else:
n.append(1)
m = m1
return string.join([str(i) for i in n], '')
def twosComplementDecimalToFloat(intBits,decBits,binString):
n = 0.0
if binString[0] == "1":
n = -1*pow(2,intBits-1)
for i in range(intBits-1):
n += int(binString[intBits-1-i])*pow(2,i)
for i in range(1,decBits+1):
n += int(binString[intBits-1+i])*pow(2,-1*i)
return n
You can use the Binary fractions package. This package implements TwosComplement with binary integers and binary fractions. You can convert binary-fraction strings into their twos complement and vice-versa
Example:
>>> from binary_fractions import TwosComplement
>>> str(TwosComplement(-1.5)) # float --> TwosComplement
'10.1'
>>> str(TwosComplement(1.5)) # float --> TwosComplement
'01.1'
>>> TwosComplement.to_float("11111111111") # TwosComplement --> float
-1.0
>>> TwosComplement.to_float("11111111100") # TwosComplement --> float
-4.0
>>> str(TwosComplement(5)) # int --> TwosComplement
'0101'
To use this with Binary's instead of float's you can use the Binary class inside the same package.
PS: Shameless plug, I'm the author of this package.

Float to binary

I'm trying to convert a floating point number to binary representation; how can I achieve this?
My goal is, however, not to be limited by 2m so I'm hoping for something that could be easily extended to any base (3, 4, 8) ecc.
I've got a straightforward implementation so far for integers:
import string
LETTER = '0123456789' + string.ascii_lowercase
def convert_int(num, base):
if base == 1:
print "WARNING! ASKING FOR BASE = 1"
return '1' * num if num != 0 else '0'
if base > 36: raise ValueError('base must be >= 1 and <= 36')
num, rest = divmod(num, base)
rest = [LETTER[rest]]
while num >= base:
num, r = divmod(num, base)
rest.append(LETTER[r])
rest.reverse()
return (LETTER[num] if num else '') + ''.join(str(x) for x in rest)
any help appreciated :)
edit:
def convert_float(num, base, digits=None):
num = float(num)
if digits is None: digits = 6
num = int(round(num * pow(base, digits)))
num = convert_int(num, base)
num = num[:-digits] + '.' + num[:digits]
if num.startswith('.'): num = '0' + num
return num
is that right? why do i get this behaviour?
>>> convert_float(1289.2893, 16)
'509.5094a0'
>>> float.hex(1289.2983)
'0x1.42531758e2196p+10'
p.s.
How to convert float number to Binary?
I've read that discussion, but I don't get the answer.. I mean, does it work only for 0.25, 0.125? and I dont understand the phrase 'must be in reverse order'...
For floats there is built-in method hex().
http://docs.python.org/library/stdtypes.html#float.hex
It gives you the hexadecimal representation of a given number. And translation form hex to binary is trivial.
For example:
In [15]: float.hex(1.25)
Out[15]: '0x1.4000000000000p+0'
In [16]: float.hex(8.25)
Out[16]: '0x1.0800000000000p+3'
Next answer with a bit of theory.
Explanation below does not explain IEEE Floating Point standard only general ideas concerning representation of floating point numbers
Every float number is represented as a fractional part multiplied by an exponent multiplied by a sign. Additionally there is so called bias for exponent, which will be explained bellow.
So we have
Sign bit
Fractional part digits
Exponent part digits
Example for base 2 with 8 bit fraction and 8 bit exponent
Bits in fraction part tell us which summands (numbers to be added) from sequence below are to be included in represented number value
2^-1 + 2^-2 + 2^-3 + 2^-4 + 2^-5 + 2^-6 + 2^-7 + 2^-8
So if you have say 01101101 in fractional part it gives
0*2^-1 + 1*2^-2 + 1*2^-3 + 0*2^-4 + 1*2^-5 + 1*2^-6 + 0*2^-7 + 1*2^-8 = 0.42578125
Now non-zero numbers that are representable that way fall between
2 ** -8 = 0.00390625 and 1 - 2**-8 = 0.99609375
Here the exponent part comes in. Exponent allows us to represent very big numbers by multiplying the fraction part by exponent. So if we have an 8bit exponent we can multiply the resulting fraction by numbers between 0 and 2^255.
So going back to example above let's take exponent of 11000011 = 195.
We have fractional part of 01101101 = 0.42578125 and exponent part 11000011 = 195. It gives us the number 0.42578125 * 2^195, this is really big number.
So far we can represent non-zero numbers between 2^-8 * 2^0 and (1-2^-8) * 2^255. This allows for very big numbers but not for very small numbers. In order to be able to represent small numbers we have to include so called bias in our exponent. It is a number that will be always subtracted from exponent in order to allow for representation of small numbers.
Let's take a bias of 127. Now all exponents are subtracted 127. So numbers that can be represented are between 2^-8 * 2^(0 - 127) and (1-2^-8) * 2^(255 - 127 = 128)
Example number is now 0.42578125 * 2^(195-127 = 68) which is still pretty big.
Example ends
In order to understand this better try to experiment with different bases and sizes for fractional and exponential part. At beginning don't try with odd bases because it only complicates things necessary.
Once you grasp how this representation works you should be able to write code to obtain representation of any number in any base, fractional/exponential part combination.
If you want to convert a float to a string with d digits after the decimal radix point:
Multiply the number by base**d.
Round to the nearest integer.
Convert the integer to a string.
Insert the . character d digits before the end.
For example, to represent 0.1 in base 12 with 4 decimal dozenal places,
0.1 × 124 = 2073.6
Round to nearest integer → 2074
Convert to string → 124A
Add radix point → 0.124A
This isn't the same style of binary representation that you want, but this will convert an IEEE 754 into it's sign, mantissa and base, which can be used to create a hex representation in a fairly straightforward fashion. Note that the 'value' of the mantissa is 1+BINARY, where BINARY is the binary representation - hence the -1 in the return.
I wrote this code and am declaring it public domain.
def disect_float(f):
f = float(f); #fixes passing integers
sign = 0x00; #positive
exp = 0;
mant = 0;
if(f < 0): #make f positive, store the sign
sign = '-'; #negative
f = -f;
#get the mantissa by itself
while(f % 1 > 0): #exp is positive
f*=2
exp+=1
#while(f % 1 > 0):
tf = f/2;
while(tf % 1 <= 0): #exp is negative
exp-=1;
f=tf;
tf=f/2;
if(exp < -1024): break;
mant=int(f);
return sign, mant-1, exp;
There is one trick that i observed that we can do using simple string manipulations. I felt this method to be simpler than other methods that i came across.
s = "1101.0101"
s1, s2 = s.split(".")
s1 = int(s1, 2)
s2 = int(s2, 2)/(2**len(s2))
x = s1+s2
print(x)
Output :
13.3125
Hope it will be helpful to someone.
Answering the title directly and using float.hex, which uses 64bit IEE754, one could write this method:
def float_to_bin(x):
if x == 0:
return "0" * 64
w, sign = (float.hex(x), 0) if x > 0 else (float.hex(x)[1:], 1)
mantissa, exp = int(w[4:17], 16), int(w[18:])
return "{}{:011b}{:052b}".format(sign, exp + 1023, mantissa)
float_to_bin(-0.001) # '1011111101010000000010110011111101011000011011100110110100101010'
Note however, this does not work for NaN and Inf.

Categories