9

let's say

numbers = [ 0.7653, 10.2, 100.2325, 500.9874 ]

I'd like to output the numbers with a fixed width by varying the number of decimal places to get an output like this:

0.7653
10.200
100.23
500.98

is there an easy way to do this? I've been trying with various %f and %d configurations with no luck.

falsetru
  • 357,413
  • 63
  • 732
  • 636
attamatti
  • 183
  • 1
  • 10

2 Answers2

20

Combining two str.format / format calls:

numbers = [ 0.7653, 10.2, 100.2325, 500.9874 ]
>>> for n in numbers:
...     print('{:.6s}'.format('{:0.4f}'.format(n)))
...     #  OR format(format(n, '0.4f'), '.6s')
...
0.7653
10.200
100.23
500.98

or % operators:

>>> for n in numbers:
...     print('%.6s' % ('%.4f' % n))
...
0.7653
10.200
100.23
500.98

Alternatively, you can use slicing:

>>> for n in numbers:
...     print(('%.4f' % n)[:6])
...
0.7653
10.200
100.23
500.98
falsetru
  • 357,413
  • 63
  • 732
  • 636
4

Unfortunately, there is no out-of-box solution for this problem. Moreover, the solution with string slicing does not adequately handles rounding as well as overflows.

Therefore, it seems that one has to write an own function like this:

def to_fixed_width(n, max_width, allow_overflow = True, do_round = True):
    if do_round:
        for i in range(max_width - 2, -1, -1):
            str0 = '{:.{}f}'.format(n, i)
            if len(str0) <= max_width:
                break
    else:
        str0 = '{:.42f}'.format(n)
        int_part_len = str0.index('.')
        if int_part_len <= max_width - 2:
            str0 = str0[:max_width]
        else:
            str0 = str0[:int_part_len]
    if (not allow_overflow) and (len(str0) > max_width):
        raise OverflowError("Impossible to represent in fixed-width non-scientific format")
    return str0

The resulting behavior:

>>> to_fixed_width(0.7653, 6)
'0.7653'
>>> to_fixed_width(10.2, 6)
'10.200'
>>> to_fixed_width(100.2325, 6)
'100.23'
>>> to_fixed_width(500.9874, 6)
'500.99'
>>> to_fixed_width(500.9874, 6, do_round = False)
'500.98'

More examples:

>>> to_fixed_width(-0.3, 6)
'-0.300'
>>> to_fixed_width(0.000001, 6)
'0.0000'
>>> to_fixed_width(999.99, 6)
'999.99'
>>> to_fixed_width(999.999, 6)
'1000.0'
>>> to_fixed_width(1000.4499, 6)
'1000.4'
>>> to_fixed_width(1000.4499, 6, do_round = False)
'1000.4'
>>> to_fixed_width(12345.6, 6)
'12346'
>>> to_fixed_width(1234567, 6)
'1234567'
>>> to_fixed_width(1234567, 6, allow_overflow = False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 15, in to_fixed_width
OverflowError: Impossible to represent in fixed-width non-scientific format
>>> to_fixed_width(float('nan'), 6)
'nan'
Roman
  • 2,225
  • 5
  • 26
  • 55
  • This is an amazing general use function, thanks @Roman! I exclusively needed the case (allow_overflow=False, do_round=True), so I use a modified version of your function. – AlexM Dec 03 '19 at 19:42