2

I would like to format my floats with a fixed amount of digits. Right now I'm doing the following

format="%6.6g"
print(format%0.00215165)
print(format%1.23260)
print(format%145.5655)

But this outputs

0.00215165
1.2326
145.565

I also tried format="%6.6f" but it doesn't really give what I want either...

0.002152
1.232600
145.565500

What would be a good way to format the numbers so that all of them have exactly width 6 (and no spaces) like so ?

0.002152
1.232600
145.5655
Jannes Braet
  • 187
  • 3
  • 11
  • With rounding, I also only control the amount of digits after the period. But I want less digits after the period if theres more digits in front of the period. – Jannes Braet Apr 26 '19 at 08:54
  • 1
    I would say, convert the float to string after formatting, then only take the first 6 characters of the string, then reconvert to float! – Devesh Kumar Singh Apr 26 '19 at 10:34

1 Answers1

5

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.

BoarGules
  • 16,440
  • 2
  • 27
  • 44