numbers = [23.23, 0.1233, 1.0, 4.223, 9887.2]
for x in numbers:
print("{:10.4f}".format(x))
prints
23.2300
0.1233
1.0000
4.2230
9887.2000
The format specifier inside the curly braces follows the Python format string syntax. Specifically, in this case, it consists of the following parts:
- The empty string before the colon means "take the next provided argument to
format()" – in this case thexas the only argument. - The
10.4fpart after the colon is the format specification. - The
fdenotes fixed-point notation. - The
10is the total width of the field being printed, lefted-padded by spaces. - The
4is the number of digits after the decimal point.
numbers = [23.23, 0.1233, 1.0, 4.223, 9887.2]
for x in numbers:
print("{:10.4f}".format(x))
prints
23.2300
0.1233
1.0000
4.2230
9887.2000
The format specifier inside the curly braces follows the Python format string syntax. Specifically, in this case, it consists of the following parts:
- The empty string before the colon means "take the next provided argument to
format()" – in this case thexas the only argument. - The
10.4fpart after the colon is the format specification. - The
fdenotes fixed-point notation. - The
10is the total width of the field being printed, lefted-padded by spaces. - The
4is the number of digits after the decimal point.
It has been a few years since this was answered, but as of Python 3.6 (PEP498) you could use the new f-strings:
numbers = [23.23, 0.123334987, 1, 4.223, 9887.2]
for number in numbers:
print(f'{number:9.4f}')
Prints:
23.2300
0.1233
1.0000
4.2230
9887.2000
string - Python: How do I format numbers for a fixed width? - Stack Overflow
Python format Integer into fixed length strings - Stack Overflow
python - Fixed-width number formatting - Stack Overflow
string - How to format a floating number to maximum fixed width in Python - Stack Overflow
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
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'
I simply took the answer by @Harvey251 but split into test part and the part we need in production.
Usage would be:
# save the code at the end as formatfloat.py and then
import formatfloat
# do this first
width = 8
ff8 = formatfloat.FormatFloat(width)
# now use ff8 whenever you need
print(ff8(12345678901234))
And here is the solution. Save the code as formatfloat.py and import it to use FlotFormat class. As I said below, loop part of calculation better be moved to init part of the FormatFlot class.
import unittest
class FormatFloat:
def __init__(self, width = 8):
self.width = width
self.maxnum = int('9'*(width - 1)) # 9999999
self.minnum = -int('9'*(width - 2)) # -999999
def __call__(self, x):
# for small numbers
# if -999,999 < given < 9,999,999:
if x > self.minnum and x < self.maxnum:
# o = f'{x:7}'
o = f'{x:{self.width - 1}}'
# converting int to float without adding zero
if '.' not in o:
o += '.'
# float longer than 8 will need rounding to fit width
elif len(o) > self.width:
# output = str(round(x, 7 - str(x).index(".")))
o = str(round(x, self.width-1 - str(x).index('.')))
else:
# for exponents
# added a loop for super large numbers or negative as "-" is another char
# Added max(max_char, 5) to account for max length of less
# than 5, was having too much fun
# TODO can i come up with a threshold value for these up front,
# so that i dont have to do this calc for every value??
for n in range(max(self.width, 5) - 5, 0, -1):
fill = f'.{n}e'
o = f'{x:{fill}}'.replace('+0', '+')
# if all good stop looping
if len(o) == self.width:
break
else:
raise ValueError(f"Number is too large to fit in {self.width} characters", x)
return o
class TestFormatFloat(unittest.TestCase):
def test_all(self):
test = (
("1234567.", 1234567),
("-123456.", -123456),
("1.23e+13", 12345678901234),
("123.4567", 123.4567),
("123.4568", 123.45678),
("1.234568", 1.2345678),
("0.123457", 0.12345678),
(" 1234.", 1234),
("1.235e+7", 12345678),
("-1.23e+6", -1234567),
)
width = 8
ff8 = FormatFloat(width)
for expected, given in test:
output = ff8(given)
self.assertEqual(len(output), width, msg=output)
self.assertEqual(output, expected, msg=given)
if __name__ == '__main__':
unittest.main()
I've made a slight addition to yosukesabai's contribution to account for the rare case where rounding will make the width of the string 7 characters instead of 8!
class FormatFloat:
def __init__(self, width = 8):
self.width = width
self.maxnum = int('9'*(width - 1)) # 9999999
self.minnum = -int('9'*(width - 2)) # -999999
def __call__(self, x):
# for small numbers
# if -999,999 < given < 9,999,999:
if x > self.minnum and x < self.maxnum:
# o = f'{x:7}'
o = f'{x:{self.width - 1}}'
# converting int to float without adding zero
if '.' not in o:
o += '.'
# float longer than 8 will need rounding to fit width
elif len(o) > self.width:
# output = str(round(x, 7 - str(x).index(".")))
o = str(round(x, self.width - 1 - str(x).index('.')))
if len(o) < self.width:
o+=(self.width-len(o))*'0'
else:
# for exponents
# added a loop for super large numbers or negative as "-" is another char
# Added max(max_char, 5) to account for max length of less
# than 5, was having too much fun
# TODO can i come up with a threshold value for these up front,
# so that i dont have to do this calc for every value??
for n in range(max(self.width, 5) - 5, 0, -1):
fill = f'.{n}e'
o = f'{x:{fill}}'.replace('+0', '+')
# if all good stop looping
if len(o) == self.width:
break
else:
raise ValueError(f"Number is too large to fit in {self.width} characters", x)
return o