36

For a scientific application I need to output very precise numbers, so I have to print 15 significant figures. There are already questions on this topic here, but they all concern with truncating the digits, not printing more.

I realized that the print function converts the input float to a 10 character string. Also, I became aware of the decimal module, but that does not suit my needs.

So the question is, how can I easily print a variable amount of signifcant figures of my floats, where I need to display more than 10?

2
  • Keep in mind that a float might not actually be capable of representing the values you're using to the precision you require, which means that your calculations could very well be horribly wrong. Commented Feb 23, 2012 at 15:46
  • @Wooble This very nice answer delves into the question you're raising. It's worth a look. Commented Feb 23, 2012 at 16:02

7 Answers 7

65

Let:

>>> num = 0.0012345 

For up to 3 significant figures:

>>> f'{num:.3}' '0.00123' 

For 3 decimal places:

>>> f'{num:.3f}' '0.001' 

See the "presentation types for floating point and decimal" table at the bottom of this section for any additional requirements provided by e, E, f, F, g, G, n, %, None.

Sign up to request clarification or add additional context in comments.

5 Comments

This should be marked as the correct answer. See Wikipedia
This displays numbers in scientific format, e.g. 12.0 => "1.2e+01", which may not be what people expect.
@quantoid According to my REPL, f'{12.0:.3}' == '12.0'. But it seems you're correct when abs(float(f'{num:.3}')) >= 10**2. It's not totally unreasonable behavior either... for instance, how would you handle 1234.56? Printing either 1230 | 1230. is misleading because not a float | 0 is actually 4. Printing 1.23e4 seems the only reasonable solution here.
In any case, I think most people want to print numbers s.t. abs(float(f'{num:.{d}}')) < 10**d
This answer is wrong and should be deleted. f"{4.2:.3}" produced 4.2, which is not three significant figures.
20

You could use the string formatting operator %:

In [3]: val = 1./3 In [4]: print('%.15f' % val) 0.333333333333333 

or str.format():

In [8]: print(str.format('{0:.15f}', val)) Out[8]: '0.333333333333333' 

In new code, the latter is the preferred style, although the former is still widely used.

For more info, see the documentation.

3 Comments

print('{0:.15f}'.format(val)) is also another way to do it in the new format.
Note that this does not print 15 significant digits, but just 15 digits after the decimal point. For very large or very small numbers, this does not make much sense. IMHO, using "%.15e" might be more reasonable.
Yeah, this is decimal places not significant figures.
12

To display N significant figures (not decimal places) you use the "g" format:

>>> x = 1.23 >>> print("%.2g" % x) 1.2 >>> x = 12.3 >>> print("%.2g" % x) 12 

See format spec for details on precision:

The precision is a decimal number indicating how many digits should be displayed after the decimal point for a floating point value formatted with 'f' and 'F', or before and after the decimal point for a floating point value formatted with 'g' or 'G'. For non-number types the field indicates the maximum field size - in other words, how many characters will be used from the field content. The precision is not allowed for integer values.

3 Comments

The docs on g: 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, unless the '#' option is used.
This answer is wrong and should be deleted. f"{4.2:.3g}" produced 4.2, which is not three significant figures.
Thanks, this is what I was looking for.
11

Thought the original question wanted to format n significant figures, not n decimal points. So a custom function might be required until some more native built-in types are on offer? So you'll want something like:

def float_nsf(q,n): """ Truncate a float to n significant figures. May produce overflow in very last decimal place when q < 1. This can be removed by an extra formatted print. Arguments: q : a float n : desired number of significant figures Returns: Float with only n s.f. and trailing zeros, but with a possible small overflow. """ sgn=np.sign(q) q=abs(q) n=int(np.log10(q/10.)) # Here you overwrite input n! if q<1. : val=q/(10**(n-1)) return sgn*int(val)*10.**(n-1) else: val=q/(10**n) return sgn*int(val)*10.**n 

1 Comment

This answer is wrong and should be deleted. float_nsf(4.2,3) produced 4.0, which is neither the correct answer nor three significant figures.
3

Use these two common print idioms for formatting. Its a matter of personal taste on which is better.

value = 10/3 #gives a float of 3.33333..... print '%.15f' % value print str.format('{0:.15f}', value) 

Personally I think the first is more compact and the 2nd is more explicit. Format has more features when working with multiple vals.

1 Comment

I downvoted because this gives 15 digits after the decimal point, not 15 significant digits. I deem this answer to be correct.
1

All existing answers are wrong.

Here is one that works for all cases that I've tried:

import numpy as np def float_to_nsf(f: float, n: int) -> str: """Convert a float into a string with a chosen number of significant figures. The decimal point is always included, even if trailing.""" s = np.format_float_positional(f, fractional=False, min_digits=n, precision=n) if s[0:2] == "0.": s = "0." + f"{s[2:]:0<{n}}" return s 

Comments

0

You could use this function I wrote, it seems to be working fine and it's quite simple!:

def nsf(num, n=1): """n-Significant Figures""" numstr = ("{0:.%ie}" % (n-1)).format(num) return float(numstr) 
  1. It first converts the number to a string using exponent notation
  2. Then returns it as float.

Some tests:

>>> a = 2./3 >>> b = 1./3 >>> c = 3141592 >>> print(nsf(a)) 0.7 >>> print(nsf(a, 3)) 0.667 >>> print(nsf(-a, 3)) -0.667 >>> print(nsf(b, 4)) 0.3333 >>> print(nsf(-b, 2)) -0.33 >>> print(nsf(c, 5)) 3141600.0 >>> print(nsf(-c, 6)) -3141590.0 

I hope this helps you ;)

5 Comments

Hmm, this kept spitting out numbers in exponent notation. Perhaps because I converted them to back to strings later?, i.e. str(float(...))
This answer is wrong and should be deleted. nsf(4.2,3) produced 4.2, which is not three significant figures.
@Myridium, please note that 4.2 only has 2 significant figures, the trailing zeroes are irrelevant. You may find the definition of significant figures here: - en.wikipedia.org/wiki/Significant_figures
In any case, I believe the solution provided by @MateenUlhaq is much better, i.e.: '{:.3}'.format(4.2) will output '4.2'
@ionelberdin that is incorrect. I.e. from the article you linked: "Zeros to the right of the last non-zero digit (trailing zeros) in a number with the decimal point are significant". The number 4.2 to three significant figures is 4.20.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.