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.
Related
Hopefully a simple one, I have a number, say 1234567.890 this number could be anything but will be this length.
How do I truncate the first 3 numbers so it turns into 4567.890?
This could be any number so subtracting 123000 will not work.
I'm working with map data in UTM coordinates (but that should not matter)
Example
x = 580992.528
y = 4275267.719
For x, I want 992.528
For y, I want 267.719
Note: y has an extra digit to the left of the decimal so 4 need removing
You can use slices for this:
x = 1234567.890
# This is still a float
x = float(str(x)[3:])
print(x)
Outputs:
4567.89
As [3:] gets the starts the index at 3 and continues to the end of the string
Update after your edit
The simplest way is to use Decimal:
from decimal import Decimal
def fmod(v, m=1000, /):
return float(Decimal(str(v)) % m)
print(fmod(x))
print(fmod(y))
Output
992.528
267.719
If you don't use string, you will have some problems with floating point in Python.
Demo:
n = 1234567.890
i = 0
while True:
m = int(n // 10**i)
if m < 1000:
break
i += 1
r = n % 10**i
Output:
>>> r
4567.889999999898
>>> round(r, 3)
4567.89
Same with Decimal from decimal module:
from decimal import Decimal
n = 1234567.890
n = Decimal(str(n))
i = 0
while True:
m = int(n // 10**i)
if m < 1000:
break
i += 1
r = n % 10**i
Output:
>>> r
Decimal('4567.89')
>>> float(r)
4567.89
This approach simply implements your idea.
int_len is the length of the integer part that we keep
sub is the rounded value that we will subtract the original float by
Code
Here is the code that implements your idea.
import math
def trim(n, digits):
int_len = len(str(int(n))) - digits # length of 4567
sub = math.floor(n / 10 **int_len) * 10**int_len
print(n - sub)
But as Kelly Bundy has pointed out, you can use modulo operation to avoid the complicated process of finding the subtrahend.
def trim(n, digits):
int_len = len(str(int(n))) - digits # length of 4567
print(n % 10**int_len)
Output
The floating point thing is a bit cursed and you may want to take Corralien's answer as an alternative.
>>> n = 1234567.890
>>> trim(n, 3)
4567.889999999898
def get_slice(number, split_n):
return number - (number // 10**split_n) * 10**split_n
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!
I don't quite understand what I am doing wrong as I started learning Python 4 days back. I want to do this using for loop to convert binary number into decimal number.
def binary_to_decimal(number):
i, integer = 0, 0
size = list(number)
for value in size:
integer = int(size[i]) * pow(2, i)
i += 1
print(f"the decimal representation is {integer}")
def binary_to_decimal("111")
The output I am getting is 3 not 4.
You need to aggregate your variable integer using += instead of =
def binary_to_decimal(number):
i, integer = 0, 0
size = list(number)
for value in size:
integer += int(size[i]) * pow(2, len(size)-1-i)
i += 1
print(f"the decimal representation is {integer}")
>>> binary_to_decimal("111")
the decimal representation is 7
>>> bin(7)
'0b111'
I need to convert from binary values such as '1010' to decimal values. this needs to include negative binary.
def BinaryToDecimal (n):
n1 = n
decimal = 0
i = 0
n = 0
while(n != 0):
dec = n % 10
decimal = decimal + dec * pow(2, i)
n = n//10
i += 1
print(decimal)
This is what i have so far, but it doesn't work. I'm not sure what else to do. Please help! I am not allowed to use any fancy python libraries, I am supposed to write the code manually.
This will work:
def BinaryToDecimal(n):
n = str(n)
print(int(n,2))
Python shell output
Binary to decimal:
>>> bin_str = '11111111'
>>> int(bin_str,2)
255
Decimals to binary:
>>> decimal = 255
>>> "{:b}".format(decimal)
'11111111'
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