Format decimal without trailing zeros [duplicate] - python

I have a long list of Decimals and that I have to adjust by factors of 10, 100, 1000,..... 1000000 depending on certain conditions. When I multiply them there is sometimes a useless trailing zero (though not always) that I want to get rid of. For example...
from decimal import Decimal
# outputs 25.0, PROBLEM! I would like it to output 25
print Decimal('2.5') * 10
# outputs 2567.8000, PROBLEM! I would like it to output 2567.8
print Decimal('2.5678') * 1000
Is there a function that tells the decimal object to drop these insignificant zeros? The only way I can think of doing this is to convert to a string and replace them using regular expressions.
Should probably mention that I am using python 2.6.5
EDIT
senderle's fine answer made me realize that I occasionally get a number like 250.0 which when normalized produces 2.5E+2. I guess in these cases I could try to sort them out and convert to a int

You can use the normalize method to remove extra precision.
>>> print decimal.Decimal('5.500')
5.500
>>> print decimal.Decimal('5.500').normalize()
5.5
To avoid stripping zeros to the left of the decimal point, you could do this:
def normalize_fraction(d):
normalized = d.normalize()
sign, digits, exponent = normalized.as_tuple()
if exponent > 0:
return decimal.Decimal((sign, digits + (0,) * exponent, 0))
else:
return normalized
Or more compactly, using quantize as suggested by user7116:
def normalize_fraction(d):
normalized = d.normalize()
sign, digit, exponent = normalized.as_tuple()
return normalized if exponent <= 0 else normalized.quantize(1)
You could also use to_integral() as shown here but I think using as_tuple this way is more self-documenting.
I tested these both against a few cases; please leave a comment if you find something that doesn't work.
>>> normalize_fraction(decimal.Decimal('55.5'))
Decimal('55.5')
>>> normalize_fraction(decimal.Decimal('55.500'))
Decimal('55.5')
>>> normalize_fraction(decimal.Decimal('55500'))
Decimal('55500')
>>> normalize_fraction(decimal.Decimal('555E2'))
Decimal('55500')

There's probably a better way of doing this, but you could use .rstrip('0').rstrip('.') to achieve the result that you want.
Using your numbers as an example:
>>> s = str(Decimal('2.5') * 10)
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
25
>>> s = str(Decimal('2.5678') * 1000)
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
2567.8
And here's the fix for the problem that #gerrit pointed out in the comments:
>>> s = str(Decimal('1500'))
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
1500

Answer from the Decimal FAQ in the documentation:
>>> def remove_exponent(d):
... return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5.00'))
Decimal('5')
>>> remove_exponent(Decimal('5.500'))
Decimal('5.5')
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')

Answer is mentioned in FAQ (https://docs.python.org/2/library/decimal.html#decimal-faq) but does not explain things.
To drop trailing zeros for fraction part you should use normalize:
>>> Decimal('100.2000').normalize()
Decimal('100.2')
>> Decimal('0.2000').normalize()
Decimal('0.2')
But this works different for numbers with leading zeros in sharp part:
>>> Decimal('100.0000').normalize()
Decimal('1E+2')
In this case we should use `to_integral':
>>> Decimal('100.000').to_integral()
Decimal('100')
So we could check if there's a fraction part:
>>> Decimal('100.2000') == Decimal('100.2000').to_integral()
False
>>> Decimal('100.0000') == Decimal('100.0000').to_integral()
True
And use appropriate method then:
def remove_exponent(num):
return num.to_integral() if num == num.to_integral() else num.normalize()
Try it:
>>> remove_exponent(Decimal('100.2000'))
Decimal('100.2')
>>> remove_exponent(Decimal('100.0000'))
Decimal('100')
>>> remove_exponent(Decimal('0.2000'))
Decimal('0.2')
Now we're done.

Use the format specifier %g. It seems remove to trailing zeros.
>>> "%g" % (Decimal('2.5') * 10)
'25'
>>> "%g" % (Decimal('2.5678') * 1000)
'2567.8'
It also works without the Decimal function
>>> "%g" % (2.5 * 10)
'25'
>>> "%g" % (2.5678 * 1000)
'2567.8'

I ended up doing this:
import decimal
def dropzeros(number):
mynum = decimal.Decimal(number).normalize()
# e.g 22000 --> Decimal('2.2E+4')
return mynum.__trunc__() if not mynum % 1 else float(mynum)
print dropzeros(22000.000)
22000
print dropzeros(2567.8000)
2567.8
note: casting the return value as a string will limit you to 12 significant digits

Slightly modified version of A-IV's answer
NOTE that Decimal('0.99999999999999999999999999995').normalize() will round to Decimal('1')
def trailing(s: str, char="0"):
return len(s) - len(s.rstrip(char))
def decimal_to_str(value: decimal.Decimal):
"""Convert decimal to str
* Uses exponential notation when there are more than 4 trailing zeros
* Handles decimal.InvalidOperation
"""
# to_integral_value() removes decimals
if value == value.to_integral_value():
try:
value = value.quantize(decimal.Decimal(1))
except decimal.InvalidOperation:
pass
uncast = str(value)
# use exponential notation if there are more that 4 zeros
return str(value.normalize()) if trailing(uncast) > 4 else uncast
else:
# normalize values with decimal places
return str(value.normalize())
# or str(value).rstrip('0') if rounding edgecases are a concern

You could use :g to achieve this:
'{:g}'.format(3.140)
gives
'3.14'

This should work:
'{:f}'.format(decimal.Decimal('2.5') * 10).rstrip('0').rstrip('.')

Just to show a different possibility, I used to_tuple() to achieve the same result.
def my_normalize(dec):
"""
>>> my_normalize(Decimal("12.500"))
Decimal('12.5')
>>> my_normalize(Decimal("-0.12500"))
Decimal('-0.125')
>>> my_normalize(Decimal("0.125"))
Decimal('0.125')
>>> my_normalize(Decimal("0.00125"))
Decimal('0.00125')
>>> my_normalize(Decimal("125.00"))
Decimal('125')
>>> my_normalize(Decimal("12500"))
Decimal('12500')
>>> my_normalize(Decimal("0.000"))
Decimal('0')
"""
if dec is None:
return None
sign, digs, exp = dec.as_tuple()
for i in list(reversed(digs)):
if exp >= 0 or i != 0:
break
exp += 1
digs = digs[:-1]
if not digs and exp < 0:
exp = 0
return Decimal((sign, digs, exp))

Why not use modules 10 from a multiple of 10 to check if there is remainder? No remainder means you can force int()
if (x * 10) % 10 == 0:
x = int(x)
x = 2/1
Output: 2
x = 3/2
Output: 1.5

Related

Zylabs 7.14 Lab: Reverse binary [duplicate]

Are there any canned Python methods to convert an Integer (or Long) into a binary string in Python?
There are a myriad of dec2bin() functions out on Google... But I was hoping I could use a built-in function / library.
Python's string format method can take a format spec.
>>> "{0:b}".format(37)
'100101'
Format spec docs for Python 2
Format spec docs for Python 3
If you're looking for bin() as an equivalent to hex(), it was added in python 2.6.
Example:
>>> bin(10)
'0b1010'
Python actually does have something already built in for this, the ability to do operations such as '{0:b}'.format(42), which will give you the bit pattern (in a string) for 42, or 101010.
For a more general philosophy, no language or library will give its user base everything that they desire. If you're working in an environment that doesn't provide exactly what you need, you should be collecting snippets of code as you develop to ensure you never have to write the same thing twice. Such as, for example, the pseudo-code:
define intToBinString, receiving intVal:
if intVal is equal to zero:
return "0"
set strVal to ""
while intVal is greater than zero:
if intVal is odd:
prefix "1" to strVal
else:
prefix "0" to strVal
divide intVal by two, rounding down
return strVal
which will construct your binary string based on the decimal value. Just keep in mind that's a generic bit of pseudo-code which may not be the most efficient way of doing it though, with the iterations you seem to be proposing, it won't make much difference. It's really just meant as a guideline on how it could be done.
The general idea is to use code from (in order of preference):
the language or built-in libraries.
third-party libraries with suitable licenses.
your own collection.
something new you need to write (and save in your own collection for later).
If you want a textual representation without the 0b-prefix, you could use this:
get_bin = lambda x: format(x, 'b')
print(get_bin(3))
>>> '11'
print(get_bin(-3))
>>> '-11'
When you want a n-bit representation:
get_bin = lambda x, n: format(x, 'b').zfill(n)
>>> get_bin(12, 32)
'00000000000000000000000000001100'
>>> get_bin(-12, 32)
'-00000000000000000000000000001100'
Alternatively, if you prefer having a function:
def get_bin(x, n=0):
"""
Get the binary representation of x.
Parameters
----------
x : int
n : int
Minimum number of digits. If x needs less digits in binary, the rest
is filled with zeros.
Returns
-------
str
"""
return format(x, 'b').zfill(n)
I am surprised there is no mention of a nice way to accomplish this using formatting strings that are supported in Python 3.6 and higher. TLDR:
>>> number = 1
>>> f'0b{number:08b}'
'0b00000001'
Longer story
This is functionality of formatting strings available from Python 3.6:
>>> x, y, z = 1, 2, 3
>>> f'{x} {y} {2*z}'
'1 2 6'
You can request binary as well:
>>> f'{z:b}'
'11'
Specify the width:
>>> f'{z:8b}'
' 11'
Request zero padding:
f'{z:08b}'
'00000011'
And add common prefix to signify binary number:
>>> f'0b{z:08b}'
'0b00000011'
You can also let Python add the prefix for you but I do not like it so much as the version above because you have to take the prefix into width consideration:
>>> f'{z:#010b}'
'0b00000011'
More info is available in official documentation on Formatted string literals and Format Specification Mini-Language.
As a reference:
def toBinary(n):
return ''.join(str(1 & int(n) >> i) for i in range(64)[::-1])
This function can convert a positive integer as large as 18446744073709551615, represented as string '1111111111111111111111111111111111111111111111111111111111111111'.
It can be modified to serve a much larger integer, though it may not be as handy as "{0:b}".format() or bin().
This is for python 3 and it keeps the leading zeros !
print(format(0, '08b'))
A simple way to do that is to use string format, see this page.
>> "{0:b}".format(10)
'1010'
And if you want to have a fixed length of the binary string, you can use this:
>> "{0:{fill}8b}".format(10, fill='0')
'00001010'
If two's complement is required, then the following line can be used:
'{0:{fill}{width}b}'.format((x + 2**n) % 2**n, fill='0', width=n)
where n is the width of the binary string.
one-liner with lambda:
>>> binary = lambda n: '' if n==0 else binary(n/2) + str(n%2)
test:
>>> binary(5)
'101'
EDIT:
but then :(
t1 = time()
for i in range(1000000):
binary(i)
t2 = time()
print(t2 - t1)
# 6.57236599922
in compare to
t1 = time()
for i in range(1000000):
'{0:b}'.format(i)
t2 = time()
print(t2 - t1)
# 0.68017411232
As the preceding answers mostly used format(),
here is an f-string implementation.
integer = 7
bit_count = 5
print(f'{integer:0{bit_count}b}')
Output:
00111
For convenience here is the python docs link for formatted string literals: https://docs.python.org/3/reference/lexical_analysis.html#f-strings.
Summary of alternatives:
n=42
assert "-101010" == format(-n, 'b')
assert "-101010" == "{0:b}".format(-n)
assert "-101010" == (lambda x: x >= 0 and str(bin(x))[2:] or "-" + str(bin(x))[3:])(-n)
assert "0b101010" == bin(n)
assert "101010" == bin(n)[2:] # But this won't work for negative numbers.
Contributors include John Fouhy, Tung Nguyen, mVChr, Martin Thoma. and Martijn Pieters.
>>> format(123, 'b')
'1111011'
For those of us who need to convert signed integers (range -2**(digits-1) to 2**(digits-1)-1) to 2's complement binary strings, this works:
def int2bin(integer, digits):
if integer >= 0:
return bin(integer)[2:].zfill(digits)
else:
return bin(2**digits + integer)[2:]
This produces:
>>> int2bin(10, 8)
'00001010'
>>> int2bin(-10, 8)
'11110110'
>>> int2bin(-128, 8)
'10000000'
>>> int2bin(127, 8)
'01111111'
you can do like that :
bin(10)[2:]
or :
f = str(bin(10))
c = []
c.append("".join(map(int, f[2:])))
print c
Using numpy pack/unpackbits, they are your best friends.
Examples
--------
>>> a = np.array([[2], [7], [23]], dtype=np.uint8)
>>> a
array([[ 2],
[ 7],
[23]], dtype=uint8)
>>> b = np.unpackbits(a, axis=1)
>>> b
array([[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 1, 0, 1, 1, 1]], dtype=uint8)
Yet another solution with another algorithm, by using bitwise operators.
def int2bin(val):
res=''
while val>0:
res += str(val&1)
val=val>>1 # val=val/2
return res[::-1] # reverse the string
A faster version without reversing the string.
def int2bin(val):
res=''
while val>0:
res = chr((val&1) + 0x30) + res
val=val>>1
return res
numpy.binary_repr(num, width=None)
Examples from the documentation link above:
>>> np.binary_repr(3)
'11'
>>> np.binary_repr(-3)
'-11'
>>> np.binary_repr(3, width=4)
'0011'
The two’s complement is returned when the input number is negative and width is specified:
>>> np.binary_repr(-3, width=3)
'101'
>>> np.binary_repr(-3, width=5)
'11101'
The accepted answer didn't address negative numbers, which I'll cover.
In addition to the answers above, you can also just use the bin and hex functions. And in the opposite direction, use binary notation:
>>> bin(37)
'0b100101'
>>> 0b100101
37
But with negative numbers, things get a bit more complicated. The question doesn't specify how you want to handle negative numbers.
Python just adds a negative sign so the result for -37 would be this:
>>> bin(-37)
'-0b100101'
In computer/hardware binary data, negative signs don't exist. All we have is 1's and 0's. So if you're reading or producing binary streams of data to be processed by other software/hardware, you need to first know the notation being used.
One notation is sign-magnitude notation, where the first bit represents the negative sign, and the rest is the actual value. In that case, -37 would be 0b1100101 and 37 would be 0b0100101. This looks like what python produces, but just add a 0 or 1 in front for positive / negative numbers.
More common is Two's complement notation, which seems more complicated and the result is very different from python's string formatting. You can read the details in the link, but with an 8bit signed integer -37 would be 0b11011011 and 37 would be 0b00100101.
Python has no easy way to produce these binary representations. You can use numpy to turn Two's complement binary values into python integers:
>>> import numpy as np
>>> np.int8(0b11011011)
-37
>>> np.uint8(0b11011011)
219
>>> np.uint8(0b00100101)
37
>>> np.int8(0b00100101)
37
But I don't know an easy way to do the opposite with builtin functions. The bitstring package can help though.
>>> from bitstring import BitArray
>>> arr = BitArray(int=-37, length=8)
>>> arr.uint
219
>>> arr.int
-37
>>> arr.bin
'11011011'
>>> BitArray(bin='11011011').int
-37
>>> BitArray(bin='11011011').uint
219
Python 3.6 added a new string formatting approach called formatted string literals or “f-strings”.
Example:
name = 'Bob'
number = 42
f"Hello, {name}, your number is {number:>08b}"
Output will be 'Hello, Bob, your number is 00001010!'
A discussion of this question can be found here - Here
Unless I'm misunderstanding what you mean by binary string I think the module you are looking for is struct
n=input()
print(bin(n).replace("0b", ""))
def binary(decimal) :
otherBase = ""
while decimal != 0 :
otherBase = str(decimal % 2) + otherBase
decimal //= 2
return otherBase
print binary(10)
output:
1010
Here is the code I've just implemented. This is not a method but you can use it as a ready-to-use function!
def inttobinary(number):
if number == 0:
return str(0)
result =""
while (number != 0):
remainder = number%2
number = number/2
result += str(remainder)
return result[::-1] # to invert the string
Calculator with all neccessary functions for DEC,BIN,HEX:
(made and tested with Python 3.5)
You can change the input test numbers and get the converted ones.
# CONVERTER: DEC / BIN / HEX
def dec2bin(d):
# dec -> bin
b = bin(d)
return b
def dec2hex(d):
# dec -> hex
h = hex(d)
return h
def bin2dec(b):
# bin -> dec
bin_numb="{0:b}".format(b)
d = eval(bin_numb)
return d,bin_numb
def bin2hex(b):
# bin -> hex
h = hex(b)
return h
def hex2dec(h):
# hex -> dec
d = int(h)
return d
def hex2bin(h):
# hex -> bin
b = bin(h)
return b
## TESTING NUMBERS
numb_dec = 99
numb_bin = 0b0111
numb_hex = 0xFF
## CALCULATIONS
res_dec2bin = dec2bin(numb_dec)
res_dec2hex = dec2hex(numb_dec)
res_bin2dec,bin_numb = bin2dec(numb_bin)
res_bin2hex = bin2hex(numb_bin)
res_hex2dec = hex2dec(numb_hex)
res_hex2bin = hex2bin(numb_hex)
## PRINTING
print('------- DECIMAL to BIN / HEX -------\n')
print('decimal:',numb_dec,'\nbin: ',res_dec2bin,'\nhex: ',res_dec2hex,'\n')
print('------- BINARY to DEC / HEX -------\n')
print('binary: ',bin_numb,'\ndec: ',numb_bin,'\nhex: ',res_bin2hex,'\n')
print('----- HEXADECIMAL to BIN / HEX -----\n')
print('hexadec:',hex(numb_hex),'\nbin: ',res_hex2bin,'\ndec: ',res_hex2dec,'\n')
Somewhat similar solution
def to_bin(dec):
flag = True
bin_str = ''
while flag:
remainder = dec % 2
quotient = dec / 2
if quotient == 0:
flag = False
bin_str += str(remainder)
dec = quotient
bin_str = bin_str[::-1] # reverse the string
return bin_str
here is simple solution using the divmod() fucntion which returns the reminder and the result of a division without the fraction.
def dectobin(number):
bin = ''
while (number >= 1):
number, rem = divmod(number, 2)
bin = bin + str(rem)
return bin
Here's yet another way using regular math, no loops, only recursion. (Trivial case 0 returns nothing).
def toBin(num):
if num == 0:
return ""
return toBin(num//2) + str(num%2)
print ([(toBin(i)) for i in range(10)])
['', '1', '10', '11', '100', '101', '110', '111', '1000', '1001']
To calculate binary of numbers:
print("Binary is {0:>08b}".format(16))
To calculate the Hexa decimal of a number:
print("Hexa Decimal is {0:>0x}".format(15))
To Calculate all the binary no till 16::
for i in range(17):
print("{0:>2}: binary is {0:>08b}".format(i))
To calculate Hexa decimal no till 17
for i in range(17):
print("{0:>2}: Hexa Decimal is {0:>0x}".format(i))
##as 2 digit is enogh for hexa decimal representation of a number
try:
while True:
p = ""
a = input()
while a != 0:
l = a % 2
b = a - l
a = b / 2
p = str(l) + p
print(p)
except:
print ("write 1 number")
I found a method using matrix operation to convert decimal to binary.
import numpy as np
E_mat = np.tile(E,[1,M])
M_order = pow(2,(M-1-np.array(range(M)))).T
bindata = np.remainder(np.floor(E_mat /M_order).astype(np.int),2)
Eis input decimal data,M is the binary orders. bindata is output binary data, which is in a format of 1 by M binary matrix.

How can I print any float, like 1.234e22, in a long, nicely rounded and localized format in python?

There are a few existing questions about float formatting, but none answer the following question, I think.
I'm looking for a way to print large floats in a long, nicely rounded and localized format:
>>> print magic_format(1.234e22, locale="en_US")
12,340,000,000,000,000,000,000
>>> print magic_format(1.234e22, locale="fr_FR")
12 340 000 000 000 000 000 000
Unfortunately, magic_format does not exist. ;-) How can I implement it?
Details
Here are a few ways to print floats. None of them produces the above output:
>>> x = 1.234e22
>>> print str(x)
1.234e+22
>>> print repr(x)
1.234e+22
>>> print "%f" % x
12339999999999998951424.000000
>>> print "%g" % x
1.234e+22
Fail: either I get the short version, or a non-grouping non-localized non-rounded output.
BTW, I understand that 1.234e22 cannot be stored exactly as a float, there's a necessary rounding error (that explains the odd output above). But since str, repr and "%g" % x are able to properly round that to the proper value, I would like to have the same friendly rounded number, but in a long and localized form.
Let's try localizing now...
>>> import locale
>>> locale.setlocale(locale.LC_ALL, "en_US")
'en_US'
>>> locale.format("%g", x, grouping = True)
'1.234e+22'
>>> locale.format("%f", x, grouping = True)
'12,339,999,999,999,998,951,424.000000'
>>> locale.setlocale(locale.LC_ALL, "fr_FR")
'fr_FR'
>>> locale.format("%g", x, grouping = True)
'1,234e+22'
>>> locale.format("%f", x, grouping = True)
'12339999999999998951424,000000'
Closer, but not ok. I still have the annoying rounding error, and the French localization sucks, it does not allow grouping at all.
So let's use the excellent Babel library, perhaps it can do everything I want:
>>> from babel.numbers import format_number
>>> format_number(x, locale = "en_US")
u'12,339,999,999,999,998,951,424'
>>> format_number(x, locale = "fr_FR")
u'12\xa0339\xa0999\xa0999\xa0999\xa0998\xa0951\xa0424'
Wow, really close. They even use non-breakable spaces for grouping in French, I love it. It's really too bad they still have the rounding issue.
Hey!? What if I used python Decimals?
>>> from decimal import Decimal
>>> Decimal(x)
Decimal('12339999999999998951424')
>>> Decimal("%g" % x)
Decimal('1.234E+22')
>>> "%g" % Decimal("%g" % x)
'1.234e+22'
>>> "%f" % Decimal("%g" % x)
'12339999999999998951424.000000'
Nope. I can get an exact representation of the number I want with Decimal("%g" % x), but whenever I try to display it, it's either short or converted to a bad float before it's printed.
But what if I mixed Babel and Decimals?
>>> Decimal("%g" % 1.234e22)
Decimal('1.234E+22')
>>> dx = _
>>> format_number(dx, locale = "en_US")
Traceback (most recent call last):
...
TypeError: bad operand type for abs(): 'str'
Ouch. But Babel's got a function called format_decimal, let's use that instead:
>>> from babel.numbers import format_decimal
>>> format_decimal(dx, locale = "en_US")
Traceback (most recent call last):
...
TypeError: bad operand type for abs(): 'str'
Oops, format_decimal can't format python Decimals. :-(
Ok, one last idea: I could try converting to a long.
>>> x = 1.234e22
>>> long(x)
12339999999999998951424L
>>> long(Decimal(x))
12339999999999998951424L
>>> long(Decimal("%g" % x))
12340000000000000000000L
Yes! I've got the exact number I want to format. Let's give that to Babel:
>>> format_number(long(Decimal("%g" % x)), locale = "en_US")
u'12,339,999,999,999,998,951,424'
Oh, no... Apparently Babel converts the long to a float before trying to format it. I'm out of luck, and out of ideas. :-(
If you think that this is tough, then try answering the same question for x = 1.234e-22. So far all I can print is either the short form 1.234e-22 or 0.0!
I would prefer this:
>>> print magic_format(1.234e-22, locale="en_US")
0.0000000000000000000001234
>>> print magic_format(1.234e-22, locale="fr_FR")
0,0000000000000000000001234
>>> print magic_format(1.234e-22, locale="en_US", group_frac=True)
0.000,000,000,000,000,000,000,123,400
>>> print magic_format(1.234e-22, locale="fr_FR", group_frac=True)
0,000 000 000 000 000 000 000 123 400
I can imagine writing a little function that would parse "1.234e-22" and format it nicely, but I would have to know all about the rules of number localization, and I'd rather not reinvent the wheel, Babel is supposed to do that. What should I do?
Thanks for your help. :-)
This takes a large chunk of code from selected answer from Nicely representing a floating-point number in python but incorporates Babel to handle L10N.
NOTE : Babel uses a weird unicode version of the space character for a lot of locales. Hence the if loop that mentions 'fr_FR' directly to convert it to a normal space character.
import locale
from babel.numbers import get_decimal_symbol,get_group_symbol
import decimal
# https://stackoverflow.com/questions/2663612/nicely-representing-a-floating-point-number-in-python/2663623#2663623
def float_to_decimal(f):
# http://docs.python.org/library/decimal.html#decimal-faq
"Convert a floating point number to a Decimal with no loss of information"
n, d = f.as_integer_ratio()
numerator, denominator = decimal.Decimal(n), decimal.Decimal(d)
ctx = decimal.Context(prec=60)
result = ctx.divide(numerator, denominator)
while ctx.flags[decimal.Inexact]:
ctx.flags[decimal.Inexact] = False
ctx.prec *= 2
result = ctx.divide(numerator, denominator)
return result
def f(number, sigfig):
assert(sigfig>0)
try:
d=decimal.Decimal(number)
except TypeError:
d=float_to_decimal(float(number))
sign,digits,exponent=d.as_tuple()
if len(digits) < sigfig:
digits = list(digits)
digits.extend([0] * (sigfig - len(digits)))
shift=d.adjusted()
result=int(''.join(map(str,digits[:sigfig])))
# Round the result
if len(digits)>sigfig and digits[sigfig]>=5: result+=1
result=list(str(result))
# Rounding can change the length of result
# If so, adjust shift
shift+=len(result)-sigfig
# reset len of result to sigfig
result=result[:sigfig]
if shift >= sigfig-1:
# Tack more zeros on the end
result+=['0']*(shift-sigfig+1)
elif 0<=shift:
# Place the decimal point in between digits
result.insert(shift+1,'.')
else:
# Tack zeros on the front
assert(shift<0)
result=['0.']+['0']*(-shift-1)+result
if sign:
result.insert(0,'-')
return ''.join(result)
def magic_format(num, locale="en_US", group_frac=True):
sep = get_group_symbol(locale)
if sep == get_group_symbol('fr_FR'):
sep = ' '
else:
sep = str(sep)
dec = str(get_decimal_symbol(locale))
n = float(('%E' % num)[:-4:])
sigfig = len(str(n)) - (1 if '.' in str(n) else 0)
s = f(num,sigfig)
if group_frac:
ans = ""
if '.' not in s:
point = None
new_d = ""
new_s = s[::-1]
else:
point = s.index('.')
new_d = s[point+1::]
new_s = s[:point:][::-1]
for idx,char in enumerate(new_d):
ans += char
if (idx+1)%3 == 0 and (idx+1) != len(new_d):
ans += sep
else: ans = ans[::-1] + (dec if point != None else '')
for idx,char in enumerate(new_s):
ans += char
if (idx+1)%3 == 0 and (idx+1) != len(new_s):
ans += sep
else:
ans = ans[::-1]
else:
ans = s
return ans
This chuck of code can be used as follows:
>>> magic_format(num2, locale = 'fr_FR')
'0,000 000 000 000 000 000 000 123 456 0'
>>> magic_format(num2, locale = 'de_DE')
'0,000.000.000.000.000.000.000.123.456.0'
>>> magic_format(num2)
'0.000,000,000,000,000,000,000,123,456'
>>> f(num,6)
'12345600000000000000000'
>>> f(num2,6)
'0.000000000000000000000123456'
with the f function coming from the link.

Convert base-2 binary number string to int

I'd simply like to convert a base-2 binary number string into an int, something like this:
>>> '11111111'.fromBinaryToInt()
255
Is there a way to do this in Python?
You use the built-in int() function, and pass it the base of the input number, i.e. 2 for a binary number:
>>> int('11111111', 2)
255
Here is documentation for Python 2, and for Python 3.
Just type 0b11111111 in python interactive interface:
>>> 0b11111111
255
Another way to do this is by using the bitstring module:
>>> from bitstring import BitArray
>>> b = BitArray(bin='11111111')
>>> b.uint
255
Note that the unsigned integer (uint) is different from the signed integer (int):
>>> b.int
-1
Your question is really asking for the unsigned integer representation; this is an important distinction.
The bitstring module isn't a requirement, but it has lots of performant methods for turning input into and from bits into other forms, as well as manipulating them.
Using int with base is the right way to go. I used to do this before I found int takes base also. It is basically a reduce applied on a list comprehension of the primitive way of converting binary to decimal ( e.g. 110 = 2**0 * 0 + 2 ** 1 * 1 + 2 ** 2 * 1)
add = lambda x,y : x + y
reduce(add, [int(x) * 2 ** y for x, y in zip(list(binstr), range(len(binstr) - 1, -1, -1))])
If you wanna know what is happening behind the scene, then here you go.
class Binary():
def __init__(self, binNumber):
self._binNumber = binNumber
self._binNumber = self._binNumber[::-1]
self._binNumber = list(self._binNumber)
self._x = [1]
self._count = 1
self._change = 2
self._amount = 0
print(self._ToNumber(self._binNumber))
def _ToNumber(self, number):
self._number = number
for i in range (1, len (self._number)):
self._total = self._count * self._change
self._count = self._total
self._x.append(self._count)
self._deep = zip(self._number, self._x)
for self._k, self._v in self._deep:
if self._k == '1':
self._amount += self._v
return self._amount
mo = Binary('101111110')
Here's another concise way to do it not mentioned in any of the above answers:
>>> eval('0b' + '11111111')
255
Admittedly, it's probably not very fast, and it's a very very bad idea if the string is coming from something you don't have control over that could be malicious (such as user input), but for completeness' sake, it does work.
A recursive Python implementation:
def int2bin(n):
return int2bin(n >> 1) + [n & 1] if n > 1 else [1]
If you are using python3.6 or later you can use f-string to do the
conversion:
Binary to decimal:
>>> print(f'{0b1011010:#0}')
90
>>> bin_2_decimal = int(f'{0b1011010:#0}')
>>> bin_2_decimal
90
binary to octal hexa and etc.
>>> f'{0b1011010:#o}'
'0o132' # octal
>>> f'{0b1011010:#x}'
'0x5a' # hexadecimal
>>> f'{0b1011010:#0}'
'90' # decimal
Pay attention to 2 piece of information separated by colon.
In this way, you can convert between {binary, octal, hexadecimal, decimal} to {binary, octal, hexadecimal, decimal} by changing right side of colon[:]
:#b -> converts to binary
:#o -> converts to octal
:#x -> converts to hexadecimal
:#0 -> converts to decimal as above example
Try changing left side of colon to have octal/hexadecimal/decimal.
For large matrix (10**5 rows and up) it is better to use a vectorized matmult. Pass in all rows and cols in one shot. It is extremely fast. There is no looping in python here. I originally designed it for converting many binary columns like 0/1 for like 10 different genre columns in MovieLens into a single integer for each example row.
def BitsToIntAFast(bits):
m,n = bits.shape
a = 2**np.arange(n)[::-1] # -1 reverses array of powers of 2 of same length as bits
return bits # a
For the record to go back and forth in basic python3:
a = 10
bin(a)
# '0b1010'
int(bin(a), 2)
# 10
eval(bin(a))
# 10

Display a decimal in scientific notation

How can I display Decimal('40800000000.00000000000000') as '4.08E+10'?
I've tried this:
>>> '%E' % Decimal('40800000000.00000000000000')
'4.080000E+10'
But it has those extra 0's.
from decimal import Decimal
'%.2E' % Decimal('40800000000.00000000000000')
# returns '4.08E+10'
In your '40800000000.00000000000000' there are many more significant zeros that have the same meaning as any other digit. That's why you have to tell explicitly where you want to stop.
If you want to remove all trailing zeros automatically, you can try:
def format_e(n):
a = '%E' % n
return a.split('E')[0].rstrip('0').rstrip('.') + 'E' + a.split('E')[1]
format_e(Decimal('40800000000.00000000000000'))
# '4.08E+10'
format_e(Decimal('40000000000.00000000000000'))
# '4E+10'
format_e(Decimal('40812300000.00000000000000'))
# '4.08123E+10'
Here's an example using the format() function:
>>> "{:.2E}".format(Decimal('40800000000.00000000000000'))
'4.08E+10'
Instead of format, you can also use f-strings:
>>> f"{Decimal('40800000000.00000000000000'):.2E}"
'4.08E+10'
official documentation
original format() proposal
Given your number
x = Decimal('40800000000.00000000000000')
Starting from Python 3,
'{:.2e}'.format(x)
is the recommended way to do it.
e means you want scientific notation, and .2 means you want 2 digits after the dot. So you will get x.xxE±n
No one mentioned the short form of the .format method:
Needs at least Python 3.6
f"{Decimal('40800000000.00000000000000'):.2E}"
(I believe it's the same as Cees Timmerman, just a bit shorter)
This is a consolidated list of the "Simple" Answers & Comments.
PYTHON 3
from decimal import Decimal
x = '40800000000.00000000000000'
# Converted to Float
x = Decimal(x)
# ===================================== # `Dot Format`
print("{0:.2E}".format(x))
# ===================================== # `%` Format
print("%.2E" % x)
# ===================================== # `f` Format
print(f"{x:.2E}")
# =====================================
# ALL Return: 4.08E+10
print((f"{x:.2E}") == ("%.2E" % x) == ("{0:.2E}".format(x)))
# True
print(type(f"{x:.2E}") == type("%.2E" % x) == type("{0:.2E}".format(x)))
# True
# =====================================
OR Without IMPORT's
# NO IMPORT NEEDED FOR BASIC FLOATS
y = '40800000000.00000000000000'
y = float(y)
# ===================================== # `Dot Format`
print("{0:.2E}".format(y))
# ===================================== # `%` Format
print("%.2E" % y)
# ===================================== # `f` Format
print(f"{y:.2E}")
# =====================================
# ALL Return: 4.08E+10
print((f"{y:.2E}") == ("%.2E" % y) == ("{0:.2E}".format(y)))
# True
print(type(f"{y:.2E}") == type("%.2E" % y) == type("{0:.2E}".format(y)))
# True
# =====================================
Comparing
# =====================================
x
# Decimal('40800000000.00000000000000')
y
# 40800000000.0
type(x)
# <class 'decimal.Decimal'>
type(y)
# <class 'float'>
x == y
# True
type(x) == type(y)
# False
x
# Decimal('40800000000.00000000000000')
y
# 40800000000.0
So for Python 3, you can switch between any of the three for now.
My Fav:
print("{0:.2E}".format(y))
See tables from Python string formatting to select the proper format layout. In your case it's %.2E.
This worked best for me:
import decimal
'%.2E' % decimal.Decimal('40800000000.00000000000000')
# 4.08E+10
My decimals are too big for %E so I had to improvize:
def format_decimal(x, prec=2):
tup = x.as_tuple()
digits = list(tup.digits[:prec + 1])
sign = '-' if tup.sign else ''
dec = ''.join(str(i) for i in digits[1:])
exp = x.adjusted()
return '{sign}{int}.{dec}e{exp}'.format(sign=sign, int=digits[0], dec=dec, exp=exp)
Here's an example usage:
>>> n = decimal.Decimal(4.3) ** 12314
>>> print format_decimal(n)
3.39e7800
>>> print '%e' % n
inf
To convert a Decimal to scientific notation without needing to specify the precision in the format string, and without including trailing zeros, I'm currently using
def sci_str(dec):
return ('{:.' + str(len(dec.normalize().as_tuple().digits) - 1) + 'E}').format(dec)
print( sci_str( Decimal('123.456000') ) ) # 1.23456E+2
To keep any trailing zeros, just remove the normalize().
I prefer Python 3.x way.
cal = 123.4567
print(f"result {cal:.4E}")
4 indicates how many digits are shown shown in the floating part.
cal = 123.4567
totalDigitInFloatingPArt = 4
print(f"result {cal:.{totalDigitInFloatingPArt}E} ")
Adding an updated answer to show how to apply e notation to small numbers only
value = 0.1
a = "{:,}".format(value) if value >= 0.001 else "{:,.3e}".format(value)
print(a) # 0.1
value = 0.00002488
a = "{:,}".format(value) if value >= 0.001 else "{:,.3e}".format(value)
print(a) # 2.488e-05
Here is the simplest one I could find.
format(40800000000.00000000000000, '.2E')
#'4.08E+10'
('E' is not case sensitive. You can also use '.2e')
def formatE_decimal(x, prec=2):
""" Examples:
>>> formatE_decimal('0.1613965',10)
'1.6139650000E-01'
>>> formatE_decimal('0.1613965',5)
'1.61397E-01'
>>> formatE_decimal('0.9995',2)
'1.00E+00'
"""
xx=decimal.Decimal(x) if type(x)==type("") else x
tup = xx.as_tuple()
xx=xx.quantize( decimal.Decimal("1E{0}".format(len(tup[1])+tup[2]-prec-1)), decimal.ROUND_HALF_UP )
tup = xx.as_tuple()
exp = xx.adjusted()
sign = '-' if tup.sign else ''
dec = ''.join(str(i) for i in tup[1][1:prec+1])
if prec>0:
return '{sign}{int}.{dec}E{exp:+03d}'.format(sign=sign, int=tup[1][0], dec=dec, exp=exp)
elif prec==0:
return '{sign}{int}E{exp:+03d}'.format(sign=sign, int=tup[1][0], exp=exp)
else:
return None

How to get numbers after decimal point?

How do I get the numbers after a decimal point?
For example, if I have 5.55, how do i get .55?
5.55 % 1
Keep in mind this won't help you with floating point rounding problems. I.e., you may get:
0.550000000001
Or otherwise a little off the 0.55 you are expecting.
Use modf:
>>> import math
>>> frac, whole = math.modf(2.5)
>>> frac
0.5
>>> whole
2.0
What about:
a = 1.3927278749291
b = a - int(a)
b
>> 0.39272787492910011
Or, using numpy:
import numpy
a = 1.3927278749291
b = a - numpy.fix(a)
Using the decimal module from the standard library, you can retain the original precision and avoid floating point rounding issues:
>>> from decimal import Decimal
>>> Decimal('4.20') % 1
Decimal('0.20')
As kindall notes in the comments, you'll have to convert native floats to strings first.
An easy approach for you:
number_dec = str(number-int(number))[1:]
Try Modulo:
5.55%1 = 0.54999999999999982
To make it work with both positive and negative numbers:
try abs(x)%1. For negative numbers, without with abs, it will go wrong.
5.55 % 1
output 0.5499999999999998
-5.55 % 1
output 0.4500000000000002
import math
orig = 5.55
whole = math.floor(orig) # whole = 5.0
frac = orig - whole # frac = 0.55
similar to the accepted answer, even easier approach using strings would be
def number_after_decimal(number1):
number = str(number1)
if 'e-' in number: # scientific notation
number_dec = format(float(number), '.%df'%(len(number.split(".")[1].split("e-")[0])+int(number.split('e-')[1])))
elif "." in number: # quick check if it is decimal
number_dec = number.split(".")[1]
return number_dec
>>> n=5.55
>>> if "." in str(n):
... print "."+str(n).split(".")[-1]
...
.55
Just using simple operator division '/' and floor division '//' you can easily get the fraction part of any given float.
number = 5.55
result = (number/1) - (number//1)
print(result)
Sometimes trailing zeros matter
In [4]: def split_float(x):
...: '''split float into parts before and after the decimal'''
...: before, after = str(x).split('.')
...: return int(before), (int(after)*10 if len(after)==1 else int(after))
...:
...:
In [5]: split_float(105.10)
Out[5]: (105, 10)
In [6]: split_float(105.01)
Out[6]: (105, 1)
In [7]: split_float(105.12)
Out[7]: (105, 12)
Another example using modf
from math import modf
number = 1.0124584
# [0] decimal, [1] integer
result = modf(number)
print(result[0])
# output = 0124584
print(result[1])
# output = 1
This is a solution I tried:
num = 45.7234
(whole, frac) = (int(num), int(str(num)[(len(str(int(num)))+1):]))
Float numbers are not stored in decimal (base10) format. Have a read through the python documentation on this to satisfy yourself why. Therefore, to get a base10 representation from a float is not advisable.
Now there are tools which allow storage of numeric data in decimal format. Below is an example using the Decimal library.
from decimal import *
x = Decimal('0.341343214124443151466')
str(x)[-2:] == '66' # True
y = 0.341343214124443151466
str(y)[-2:] == '66' # False
Use floor and subtract the result from the original number:
>> import math #gives you floor.
>> t = 5.55 #Give a variable 5.55
>> x = math.floor(t) #floor returns t rounded down to 5..
>> z = t - x #z = 5.55 - 5 = 0.55
Example:
import math
x = 5.55
print((math.floor(x*100)%100))
This is will give you two numbers after the decimal point, 55 from that example. If you need one number you reduce by 10 the above calculations or increase depending on how many numbers you want after the decimal.
import math
x = 1245342664.6
print( (math.floor(x*1000)%1000) //100 )
It definitely worked
Another option would be to use the re module with re.findall or re.search:
import re
def get_decimcal(n: float) -> float:
return float(re.search(r'\.\d+', str(n)).group(0))
def get_decimcal_2(n: float) -> float:
return float(re.findall(r'\.\d+', str(n))[0])
def get_int(n: float) -> int:
return int(n)
print(get_decimcal(5.55))
print(get_decimcal_2(5.55))
print(get_int(5.55))
Output
0.55
0.55
5
If you wish to simplify/modify/explore the expression, it's been explained on the top right panel of regex101.com. If you'd like, you can also watch in this link, how it would match against some sample inputs.
Source
How to get rid of additional floating numbers in python subtraction?
You can use this:
number = 5.55
int(str(number).split('.')[1])
This is only if you want toget the first decimal
print(int(float(input()) * 10) % 10)
Or you can try this
num = float(input())
b = num - int(num)
c = b * 10
print(int(c))
Using math module
speed of this has to be tested
from math import floor
def get_decimal(number):
'''returns number - floor of number'''
return number-floor(number)
Example:
n = 765.126357123
get_decimal(n)
0.12635712300004798
def fractional_part(numerator, denominator):
# Operate with numerator and denominator to
# keep just the fractional part of the quotient
if denominator == 0:
return 0
else:
return (numerator/ denominator)-(numerator // denominator)
print(fractional_part(5, 5)) # Should be 0
print(fractional_part(5, 4)) # Should be 0.25
print(fractional_part(5, 3)) # Should be 0.66...
print(fractional_part(5, 2)) # Should be 0.5
print(fractional_part(5, 0)) # Should be 0
print(fractional_part(0, 5)) # Should be 0
Easier if the input is a string, we can use split()
decimal = input("Input decimal number: ") #123.456
# split 123.456 by dot = ['123', '456']
after_coma = decimal.split('.')[1]
# because only index 1 is taken then '456'
print(after_coma) # '456'
if you want to make a number type
print(int(after_coma)) # 456
a = 12.587
b = float('0.' + str(a).split('.')[-1])
What about:
a = 1.234
b = a - int(a)
length = len(str(a))
round(b, length-2)
Output:
print(b)
0.23399999999999999
round(b, length-2)
0.234
Since the round is sent to a the length of the string of decimals ('0.234'), we can just minus 2 to not count the '0.', and figure out the desired number of decimal points. This should work most times, unless you have lots of decimal places and the rounding error when calculating b interferes with the second parameter of round.
You may want to try this:
your_num = 5.55
n = len(str(int(your_num)))
float('0' + str(your_num)[n:])
It will return 0.55.
number=5.55
decimal=(number-int(number))
decimal_1=round(decimal,2)
print(decimal)
print(decimal_1)
output: 0.55
See what I often do to obtain numbers after the decimal point in python
3:
a=1.22
dec=str(a).split('.')
dec= int(dec[1])
If you are using pandas:
df['decimals'] = df['original_number'].mod(1)

Categories

Resources