How can I format a float so that it doesn't contain trailing zeros? In other words, I want the resulting string to be as short as possible.
For example:
3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"
How can I format a float so that it doesn't contain trailing zeros? In other words, I want the resulting string to be as short as possible.
For example:
3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"
Me, I'd do ('%f' % x).rstrip('0').rstrip('.')
-- guarantees fixed-point formatting rather than scientific notation, etc etc. Yeah, not as slick and elegant as %g
, but, it works (and I don't know how to force %g
to never use scientific notation;-).
'%.2f' % -0.0001
will leave you with -0.00
and ultimately -0
.
'f' Fixed point. Displays the number as a fixed-point number. The default precision is 6.
You would have to use '%0.7f' in the above solution.
'%0.15f'
is a bad idea, because weird stuff starts to happen.
Sep 1 '15 at 15:38
print('In the middle {} and something else'.format('{:f}'.format(a).rstrip('0')))
Apr 28 '18 at 8:10
You could use %g
to achieve this:
'%g'%(3.140)
or, with Python ≥ 2.6:
'{0:g}'.format(3.140)
or, with Python ≥ 3.6:
f'{3.140:g}'
From the docs for format
: g
causes (among other things)
insignificant trailing zeros [to be] removed from the significand, and the decimal point is also removed if there are no remaining digits following it.
'{0:...}'.format(value)
when you could use format(value, '...')
? That avoids having to parse out the format specifier from a template string that is otherwise empty.
format(v, '2.5f')
take ~10% longer than '{:2.5f}'.format(v)
. Even if it didn't, I tend to use the str
method form because when I need to tweak it, add additional values to it, etc., there is less to change. Of course, as of 3.6 we have f-strings for most purposes. :-)
Aug 25 '18 at 2:12
f"{var:g}"
where var
is a float variable.
Sep 24 '19 at 15:15
After looking over answers to several similar questions, this seems to be the best solution for me:
def floatToString(inputValue):
return ('%.15f' % inputValue).rstrip('0').rstrip('.')
My reasoning:
%g
doesn't get rid of scientific notation.
>>> '%g' % 0.000035
'3.5e-05'
15 decimal places seems to avoid strange behavior and has plenty of precision for my needs.
>>> ('%.15f' % 1.35).rstrip('0').rstrip('.')
'1.35'
>>> ('%.16f' % 1.35).rstrip('0').rstrip('.')
'1.3500000000000001'
I could have used format(inputValue, '.15f').
instead of '%.15f' % inputValue
, but that is a bit slower (~30%).
I could have used Decimal(inputValue).normalize()
, but this has a few issues as well. For one, it is A LOT slower (~11x). I also found that although it has pretty great precision, it still suffers from precision loss when using normalize()
.
>>> Decimal('0.21000000000000000000000000006').normalize()
Decimal('0.2100000000000000000000000001')
>>> Decimal('0.21000000000000000000000000006')
Decimal('0.21000000000000000000000000006')
Most importantly, I would still be converting to Decimal
from a float
which can make you end up with something other than the number you put in there. I think Decimal
works best when the arithmetic stays in Decimal
and the Decimal
is initialized with a string.
>>> Decimal(1.35)
Decimal('1.350000000000000088817841970012523233890533447265625')
>>> Decimal('1.35')
Decimal('1.35')
I'm sure the precision issue of Decimal.normalize()
can be adjusted to what is needed using context settings, but considering the already slow speed and not needing ridiculous precision and the fact that I'd still be converting from a float and losing precision anyway, I didn't think it was worth pursuing.
I'm not concerned with the possible "-0" result since -0.0 is a valid floating point number and it would probably be a rare occurrence anyway, but since you did mention you want to keep the string result as short as possible, you could always use an extra conditional at very little extra speed cost.
def floatToString(inputValue):
result = ('%.15f' % inputValue).rstrip('0').rstrip('.')
return '0' if result == '-0' else result
floatToString(12345.6)
returns '12345.600000000000364'
for example. Decreasing the 15 in %.15f
to a lower number solves it in this example, but that value needs to be decreased more and more as the number gets larger. It could be dynamically calculated based on the log-base-10 of the number, but that quickly becomes very complicated.
Mar 29 '17 at 3:21
result = ('%15f' % val).rstrip('0').rstrip('.').lstrip(' ')
Jul 6 '18 at 17:08
>>>12345.600000000000364 == 12345.6
True
What about trying the easiest and probably most effective approach? The method normalize() removes all the rightmost trailing zeros.
from decimal import Decimal
print (Decimal('0.001000').normalize())
# Result: 0.001
Works in Python 2 and Python 3.
-- Updated --
The only problem as @BobStein-VisiBone pointed out, is that numbers like 10, 100, 1000... will be displayed in exponential representation. This can be easily fixed using the following function instead:
from decimal import Decimal
def format_float(f):
d = Decimal(str(f));
return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
Here's a solution that worked for me. It's a blend of the solution by PolyMesh and use of the new .format()
syntax.
for num in 3, 3., 3.0, 3.1, 3.14, 3.140:
print('{0:.2f}'.format(num).rstrip('0').rstrip('.'))
Output:
3
3
3
3.1
3.14
3.14
3.141
) as the .2f
is hard-coded.
You can simply use format() to achieve this:
format(3.140, '.10g')
where 10 is the precision you want.
While formatting is likely that most Pythonic way, here is an alternate solution using the more_itertools.rstrip
tool.
import more_itertools as mit
def fmt(num, pred=None):
iterable = str(num)
predicate = pred if pred is not None else lambda x: x in {".", "0"}
return "".join(mit.rstrip(iterable, predicate))
assert fmt(3) == "3"
assert fmt(3.) == "3"
assert fmt(3.0) == "3"
assert fmt(3.1) == "3.1"
assert fmt(3.14) == "3.14"
assert fmt(3.140) == "3.14"
assert fmt(3.14000) == "3.14"
assert fmt("3,0", pred=lambda x: x in set(",0")) == "3"
The number is converted to a string, which is stripped of trailing characters that satisfy a predicate. The function definition fmt
is not required, but it is used here to test assertions, which all pass. Note: it works on string inputs and accepts optional predicates.
See also details on this third-party library, more_itertools
.
>>> str(a if a % 1 else int(a))
a if a % 1 else int(a)
is correct. Question needs output in string , So I just added str
a % 1
is truthy because it is non-zero. I implicitly and wrongly perceived it as a % 1 == 0
.
if you want something that works both on numeric or string input:
def num(s):
""" 3.0 -> 3, 3.001000 -> 3.001 otherwise return s """
s = str(s)
try:
int(float(s))
return s.rstrip('0').rstrip('.')
except ValueError:
return s
>>> for n in [3, 3., 3.0, 3.1, 3.14, 3.140, 3.001000 ]: print(num(n))
...
3
3
3
3.1
3.14
3.14
3.001
>>> for n in [3, 3., 3.0, 3.1, 3.14, 3.140, 3.001000 ]: print(num(str(n)))
...
3
3
3
3.1
3.14
3.14
3.001
Using the QuantiPhy package is an option. Normally QuantiPhy is used when working with numbers with units and SI scale factors, but it has a variety of nice number formatting options.
>>> from quantiphy import Quantity
>>> cases = '3 3. 3.0 3.1 3.14 3.140 3.14000'.split()
>>> for case in cases:
... q = Quantity(case)
... print(f'{case:>7} -> {q:p}')
3 -> 3
3. -> 3
3.0 -> 3
3.1 -> 3.1
3.14 -> 3.14
3.140 -> 3.14
3.14000 -> 3.14
And it will not use e-notation in this situation:
>>> cases = '3.14e-9 3.14 3.14e9'.split()
>>> for case in cases:
... q = Quantity(case)
... print(f'{case:>7} -> {q:,p}')
3.14e-9 -> 0
3.14 -> 3.14
3.14e9 -> 3,140,000,000
An alternative you might prefer is to use SI scale factors, perhaps with units.
>>> cases = '3e-9 3.14e-9 3 3.14 3e9 3.14e9'.split()
>>> for case in cases:
... q = Quantity(case, 'm')
... print(f'{case:>7} -> {q}')
3e-9 -> 3 nm
3.14e-9 -> 3.14 nm
3 -> 3 m
3.14 -> 3.14 m
3e9 -> 3 Gm
3.14e9 -> 3.14 Gm
Here's the answer:
import numpy
num1 = 3.1400
num2 = 3.000
numpy.format_float_positional(num1, 3, trim='-')
numpy.format_float_positional(num2, 3, trim='-')
output "3.14" and "3"
trim='-'
removes both the trailing zero's, and the decimal.
OP would like to remove superflouous zeros and make the resulting string as short as possible.
I find the %g exponential formatting shortens the resulting string for very large and very small values. The problem comes for values that don't need exponential notation, like 128.0, which is neither very large or very small.
Here is one way to format numbers as short strings that uses %g exponential notation only when Decimal.normalize creates strings that are too long. This might not be the fastest solution (since it does use Decimal.normalize)
def floatToString (inputValue, precision = 3):
rc = str(Decimal(inputValue).normalize())
if 'E' in rc or len(rc) > 5:
rc = '{0:.{1}g}'.format(inputValue, precision)
return rc
inputs = [128.0, 32768.0, 65536, 65536 * 2, 31.5, 1.000, 10.0]
outputs = [floatToString(i) for i in inputs]
print(outputs)
# ['128', '32768', '65536', '1.31e+05', '31.5', '1', '10']
For float you could use this:
def format_float(num):
return ('%i' if num == int(num) else '%s') % num
Test it:
>>> format_float(1.00000)
'1'
>>> format_float(1.1234567890000000000)
'1.123456789'
For Decimal see solution here: https://stackoverflow.com/a/42668598/5917543
If you can live with 3. and 3.0 appearing as "3.0", a very simple approach that right-strips zeros from float representations:
print("%s"%3.140)
(thanks @ellimilial for pointing out the exceptions)
Try this and it will allow you to add a "precision" variable to set how many decimal places you want. Just remember that it will round up. Please note that this will only work if there is a decimal in the string.
number = 4.364004650000000
precision = 2
result = "{:.{}f}".format(float(format(number).rstrip('0').rstrip('.')), precision)
Output
4.364004650000000
4.36
Use %g with big enough width, for example '%.99g'. It will print in fixed-point notation for any reasonably big number.
EDIT: it doesn't work
>>> '%.99g' % 0.0000001
'9.99999999999999954748111825886258685613938723690807819366455078125e-08'
.99
is precision, not width; kinda useful but you don't get to set the actual precision this way (other than truncating it yourself).
You can use max()
like this:
print(max(int(x), x))
x
is negative. if x < 0: print(min(x), x)
else : print(max(x), x)
Sep 29 '18 at 11:19
"{:.5g}".format(x)
I use this to format floats to trail zeros.
You can achieve that in most pythonic way like that:
python3:
"{:0.0f}".format(num)
Handling %f and you should put
%.2f
, where: .2f == .00 floats.
Example:
print "Price: %.2f" % prices[product]
Price: 1.50
3.14 == 3.140
-- They're the same floating point number. For that matter 3.140000 is the same floating-point number. The zero doesn't exist in the first place.%0.2f
and%0.3f
are the two formats required to produce the last numbers on the left. Use%0.2f
to produce the last two numbers on the right.3.0 -> "3"
is still a valid use case.print( '{:,g}'.format( X )
worked for me to output3
whereX = 6 / 2
and whenX = 5 / 2
I got an output of2.5
as expected.print("%s"%3.140)
gives you what you want. (I added an answer down down below...)