How to Format a Floating Number to Fixed Width in Python

How to format a floating number to fixed width in Python

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 the x as the only argument.
  • The 10.4f part after the colon is the format specification.
  • The f denotes fixed-point notation.
  • The 10 is the total width of the field being printed, lefted-padded by spaces.
  • The 4 is the number of digits after the decimal point.

Format floating point to a fixed width python

the g format specifier is generally good if you want scientific notation, i.e:

my_format = "{:.10g}".format

should do the right thing:

>>> list(my_format(v) for v in (0.0000000456, 12.345678987654321, 12345678987654321))
['4.56e-08', '12.34567899', '1.234567899e+16']

I realised later that the above function doesn't do what the OP wanted

Based on helpful comments from @a_guest I've come up with the following:

def my_format(v, length=10):
n = length
while n > 0:
i = len('%#.*g' % (n, v))
s = '%.*g' % (n + n - i, v)
if len(s) <= length:
return s
n -= 1
return s

I now get ['4.56e-08', '12.345679', '1.2346e+16'] back which is closer to what was wanted.

I've tested this by generating a lot of random numbers using:

from random import uniform
def rnd_float():
return uniform(-10, 10) * 10 ** (uniform(-1.6, 1.6) ** 11)

pretty arbitrary, but generates numbers reasonably close to the distribution I care about. I.e. mostly around 1, but some very small and large with decent probability.

I've passed numbers from this to my_format 100k times and I get appropriately formatted numbers back.

Format float with fixed amount of digits python

This is complicated because you want the precision (number of decimals) to depend on the available space, while the general thrust of floating-point formatting is to make the number of significant digits depend on the available space. To do what you want you need a function that computes the desired number of decimals from the log of the number. There isn't, so far as I know, a built-in function that will do this for you.

def decimals(v):
return max(0, min(6,6-int(math.log10(abs(v))))) if v else 6

This simply takes the log of number and truncates it to int. So 10-99 -> 1, 100-999 -> 2 etc. You then use that
result to work out the precision to which the number needs to be formatted. In practice the
function is more complex because of the corner cases: what to do with negative numbers, numbers that underflow, etc.
For simplicity I've deliberately left your figure of 6 decimals hard-coded 3 times in the function.

Then formatting isn't so hard:

>>> v = 0.00215165
>>> "{0:.{1}f}".format(v, decimals(v))
'0.002152'
>>> v2 = 1.23260
>>> "{0:.{1}f}".format(v2, decimals(v2))
'1.232600'
>>> v3 = 145.5655
>>> "{0:.{1}f}".format(v3, decimals(v3))
'145.5655'
>>> vz = 0e0 # behaviour with zero
>>> "{0:.{1}f}".format(vz, decimals(vz))
'0.000000'
>>> vu = 1e-10 # behaviour with underflow
>>> "{0:.{1}f}".format(vu, decimals(vu))
'0.000000'
>>> vo = 1234567 # behaviour when nearly out of space
>>> "{0:.{1}f}".format(vo, decimals(vo))
'1234567'
>>> voo = 12345678 # behaviour when all out of space
>>> "{0:.{1}f}".format(voo, decimals(voo))
'12345678'

You can use %-notation for this instead of a call to format but it is not very obvious or intuitive:

>>> "%.*f" % (decimals(v), v)
'0.002152'

You don't say what you want done with negative numbers. What this approach does is to take an extra
character to display the minus sign. If you don't want that then you need to reduce the number of
decimals for negative numbers.

How can I format a float in Python delimited by width, not by precision?

The width of the number also depends on the precision. As you want a fixed width, I would suggest you to use f strings and set the precision to be equal to the width in case the precision value is more than the width.

Syntax for f strings: f'{value:{width}.{precision}}'

  • The precision includes integer + decimal value

This is how you could use it:

    n = 3.141516
print(f'{n:{8}.{4}}')

The output that you will get is:

   3.142

Python format floating point number to fixed TOTAL width

As I suggested you in the comments, you can start by transforming the float number to a string object, and from there you can use the ljust() method of the str class, and string slicing.

Something as follows:

# Define a function that returns the desired output
format_f = lambda x: str(x + .0).ljust(6, '0')[:6]
# Let's iterate over the float numbers your provided as example
for float_ in .123456, 1.2, 12.34:
# You can call the function like in the below line
print(format_f(float_))

output

0.1234
1.2000
12.340

How to convert a floating-point number to a fixed-width string?

In order to convert a number into a set number of digits, you can convert the number into only decimals (aka 0 <= n <= 1), then remove the last characters. You can do it like that:

from math import log10

number = 123.456789
n_digits = 4

log = int(log10(number) + 1)
number /= 10**log # convert the number into only decimals

number = int(number*10**n_digits)/10**n_digits # keep the n first digits

number *= 10**log # multiply the number back

Or a more compact form:

from math import log10

number = 123.456789
n_digits= 4

log = int(log10(number) + 1) - n_digits
number = int(number/10**log)*10**log

[Edit] You should use Python round() function in a simpler way:

number = round(number, n_digits-int(log10(number))-1)

How could I format a python string from float number with fix length and width

You can specify the total width of the rendered string by putting a number before the period in the format string:

>>> '{:6.2f}'.format(12.3456)
' 12.35'

Format display of a floating number to a fixed length

You can try this as well:

def FormatIt(number, desired_length):
mantissa_length = desired_length - len(str(int(number))) - 1

return ('{:#.%df}' % (mantissa_length, )).format(number)

Output:

>>> FormatIt(182.1234567890, 8)
'182.1235'
>>> FormatIt(0.12345678901, 8)
'0.123457'


Related Topics



Leave a reply



Submit