# Formatting floats without trailing zeros

## Question:

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"
``````

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.

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;-).

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

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()
``````

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
``````

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']
``````

You can simply use format() to achieve this:

`format(3.140, '.10g')` where 10 is the precision you want.

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

``````>>> str(a if a % 1 else int(a))
``````

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
``````

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`.

You can achieve that in most pythonic way like that:

python3:

``````"{:0.0f}".format(num)
``````

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)

You can use `max()` like this:

`print(max(int(x), x))`

Handling %f and you should put

%.2f

, where:
.2f == .00 floats.

Example:

print “Price: %.2f” % prices[product]

# output:

Price: 1.50

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
``````

`"{:.5g}".format(x)`

I use this to format floats to trail zeros.

``````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.

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
``````

if you want something that works both on numeric or string input (thanks to @mike-placentra for bug hunting):

``````def num(s):
""" 3.0 -> 3, 3.001000 -> 3.001 otherwise return s """
s = str(s)
try:
int(float(s))
if '.' not in s:
s += '.0'
return s.rstrip('0').rstrip('.')
except ValueError:
return s

>>> for n in [3, 3., 3.0, 3.1, 3.14, 3.140, 3.001000, 30 ]: print(num(n))
...
3
3
3
3.1
3.14
3.14
3.001
30

>>> for n in [3, 3., 3.0, 3.1, 3.14, 3.140, 3.001000, 30 ]: print(num(str(n)))
...
3
3
3
3.1
3.14
3.14
3.001
30
``````

A new challenger has appeared.

``````def prettify_float(real: float, precision: int = 2) -> str:
'''
Prettify the passed floating-point number into a human-readable string,
rounded and truncated to the passed number of decimal places.

This converter prettifies floating-point numbers for human consumption,
producing more readable results than the default :meth:`float.__str__`
dunder method. Notably, this converter:

* Strips all ignorable trailing zeroes and decimal points from this number
(e.g., ``3`` rather than either ``3.`` or ``3.0``).
* Rounds to the passed precision for perceptual uniformity.

Parameters
----------
real : float
Arbitrary floating-point number to be prettified.
precision : int, optional
**Precision** (i.e., number of decimal places to round to). Defaults to
a precision of 2 decimal places.

Returns
----------
str
Human-readable string prettified from this floating-point number.

Raises
----------
ValueError
If this precision is negative.
'''

# If this precision is negative, raise an exception.
if precision < 0:
raise ValueError(f'Negative precision {precision} unsupported.')
# Else, this precision is non-negative.

# String prettified from this floating-point number. In order:
# * Coerce this number into a string rounded to this precision.
# * Truncate all trailing zeroes from this string.
# * Truncate any trailing decimal place if any from this string.
result = f'{real:.{precision}f}'.rstrip('0').rstrip('.')

# If rounding this string from a small negative number (e.g., "-0.001")
# yielded the anomalous result of "-0", return "0" instead; else, return
# this result as is.
return '0' if result == '-0' else result
``````

## Don’t Believe My Lies

`pytest`-style unit tests or it didn’t happen.

``````def test_prettify_float() -> None:
'''
Test usage of the :func:`prettify_float` prettifier.
'''

# Defer test-specific imports.
from pytest import raises

# Assert this function prettifies zero as expected.
assert prettify_float(0.0) == '0'

# Assert this function prettifies a negative integer as expected.
assert prettify_float(-2.0) == '-2'

# Assert this prettifier prettifies a small negative float as expected.
assert prettify_float(-0.001) == '0'

# Assert this prettifier prettifies a larger negative float as expected.
assert prettify_float(-2.718281828) == '-2.72'
assert prettify_float(-2.718281828, precision=4) == '-2.7183'

# Assert this function prettifies a positive integer as expected.
assert prettify_float(3.0) == '3'

# Assert this function prettifies a positive float as expected.
assert prettify_float(3.14159265359) == '3.14'
assert prettify_float(3.14159265359, precision=4) == '3.1416'

# Assert this prettifier raises the expected exception when passed a
# negative precision.
with raises(ValueError):
prettify_float(2.718281828, precision=-2)
``````

## %100 Pure Python

Ignore seductively simpler answers that promote:

• Trivial one liners. They all fail under common edge cases like whole numbers or small negative floats.
• Third-party packages. NumPy, QuantiPhy, and `more_itertools`? Surely you jest. Don’t increase your maintenance burden or code debt any more than you must. That said…

Throw `@beartype` on `prettify_float()` for added runtime safety and you’re golden! Your userbase will shower you with praise. Then so will I. Also, I’m pretty sure my bias is showing here.