Python float formatting - like "g", but with more digits
Asked Answered
S

4

12

I use "g" for formatting floating point values, but it switches to scientific formatting too soon for me - at the 5th digit:

>>> format(0.0001, "g")
'0.0001'
>>> format(0.00001, "g")
'1e-05'

This seems to be described in the "g" rules (the -4):

The precise rules are as follows: suppose that the result formatted with presentation type 'e' and precision p-1 would have exponent exp. Then if -4 <= exp < p, the number is formatted with presentation type 'f' and precision p-1-exp. Otherwise, the number is formatted with presentation type 'e' and precision p-1. In both cases insignificant trailing zeros are removed from the significand, and the decimal point is also removed if there are no remaining digits following it.

Is there a way to display numbers like "g", but with more digits before switching to scientific notation?

I'm thinking of using ".6f" and stripping trailing zeros, but then I won't be able to see small numbers, which need scientific notation.

Stockyard answered 7/1, 2011 at 14:16 Comment(1)
as per a comment below, ".6g" is valid format stringOutspan
E
4
from math import log10

if log10(n) < -5:
    print "%e" % n
else:
    print "%f" % n

EDIT: it's also possible to put it on a single line:

("%e" if log10(n) < -5 else "%f") % n

If n might be negative, then use log10(abs(n)) in place of log10(n).

EDIT 2: Improved based on Adal's comments:

"%e" % n if n and log10(abs(n)) < -5 else ("%f" % n).rstrip("0")

This will print 0 as "0."--if you want another representation like "0" or "0.0", you'll need to special case it with a separate if.

Exit answered 7/1, 2011 at 14:32 Comment(4)
+1 - or, as a one-liner: (('%f','%e')[log10(n) < -5]) % n - however, the solution works with positive n only.Lauro
@eumiro: Good point on the negative numbers (updated the answer), but I don't really like your one liner. Indexing a tuple by boolean values is just...non-pythonic.Exit
.rstrip("0") should be added to the "%f" output, so that the result more resembles "%g"Stockyard
a check for n == 0 is also needed (log not defined for 0)Stockyard
L
10

I had the same question.

Looking at the Python documentation it seems that g also supports precision values:

General format. For a given precision p >= 1, this rounds the number to p significant digits and then formats the result in either fixed-point format or in scientific notation, depending on its magnitude.

I don't know, why the other answers don't use this and I am not very experienced in Python, but it works.

This can be simply achieved by using format(0.00001, '.10g') where 10 is the precision you want.

Lota answered 17/1, 2017 at 15:14 Comment(3)
Thanks for pointing this out. I find some of the more obscure string formatting poorly documented or hard to find. This works for me where I'm using pandas to create a csv: dataframe.to_csv(float_format="%.12g")Outspan
I'm having trouble understanding how g with precision works: f"{10.554545:2g}" -> '10.5545' f"{10.554545:.2g}" -> '11' f"{10.554500:2g}" -> '10.5545' f"{10.554500:3g}" -> '10.5545' f"{10.554500:10g}" -> ' 10.5545' So it seems it's not really precision.Logicize
Looks like you forgot to include a point after the colon for several examples? Or was that just for testing purposes? I think the point is needed and when it is there, it does what is expected: It turns 10.554545 into 11 (two significant digits). f"{10.554545:.4g}" will probably result in 10.55. I haven't tried, though, this is just my assumption.Lota
E
4
from math import log10

if log10(n) < -5:
    print "%e" % n
else:
    print "%f" % n

EDIT: it's also possible to put it on a single line:

("%e" if log10(n) < -5 else "%f") % n

If n might be negative, then use log10(abs(n)) in place of log10(n).

EDIT 2: Improved based on Adal's comments:

"%e" % n if n and log10(abs(n)) < -5 else ("%f" % n).rstrip("0")

This will print 0 as "0."--if you want another representation like "0" or "0.0", you'll need to special case it with a separate if.

Exit answered 7/1, 2011 at 14:32 Comment(4)
+1 - or, as a one-liner: (('%f','%e')[log10(n) < -5]) % n - however, the solution works with positive n only.Lauro
@eumiro: Good point on the negative numbers (updated the answer), but I don't really like your one liner. Indexing a tuple by boolean values is just...non-pythonic.Exit
.rstrip("0") should be added to the "%f" output, so that the result more resembles "%g"Stockyard
a check for n == 0 is also needed (log not defined for 0)Stockyard
S
3

If you're using Python 2.7 you can do the following using it's advanced string formatting mini-language:

>>> '{number:.{width}f}'.format(number=0.000000000001, width=20)
'0.00000000000100000000'

You can then specify the required value of number and width dynamically.

Soldiery answered 7/1, 2011 at 15:25 Comment(1)
I still want to keep exponential notation for small numbers like 1e-25, and not display 0.0000000000 insteadStockyard
W
-1

try: if abs(log10(n)) >= 5: pass #print("Number N is :","%e" % n) #else: # print("Number N is :","%f" % n) except ValueError: print("Number N is :","%e" % n) else: if abs(log10(E)) >= 5: print("Number N is :","%e" % n) else: print("Number N is :","%f" % n)

Woodsy answered 10/2 at 0:43 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Wendelina

© 2022 - 2024 — McMap. All rights reserved.