25

Is it possible to set the number of digits to be used for printing the exponent of a floating-point number? I want to set it to 3.

Currently,

f = 0.0000870927939438012
>>> "%.14e"%f
'8.70927939438012e-05'
>>> "%0.14e"%f
'8.709279e-005'

What I want to print is: '8.70927939438012e-005'

Georgy
  • 12,464
  • 7
  • 65
  • 73
nmadzharov
  • 482
  • 2
  • 6
  • 12
  • 2
    How come second example has less precision and 3 digits in exponent? – Anurag Uniyal Mar 28 '12 at 16:00
  • On my machine "%e" % f outputs '8.709279e-05' and "%0.14e" % f outputs '8.70927939438012e-05'. Also, higher precision should be possible with libraries such as mpmath. However, I don’t know if it fits your needs. – Arseny Mar 28 '12 at 16:22

4 Answers4

22

There is a no way to control that, best way is to write a function for this e.g.

def eformat(f, prec, exp_digits):
    s = "%.*e"%(prec, f)
    mantissa, exp = s.split('e')
    # add 1 to digits as 1 is taken by sign +/-
    return "%se%+0*d"%(mantissa, exp_digits+1, int(exp))

print eformat(0.0000870927939438012, 14, 3)
print eformat(1.0000870927939438012e5, 14, 3)
print eformat(1.1e123, 4, 4)
print eformat(1.1e-123, 4, 4)

Output:

8.70927939438012e-005
1.00008709279394e+005
1.1000e+0123
1.1000e-0123
Anurag Uniyal
  • 85,954
  • 40
  • 175
  • 219
  • 2
    Anurag, there are various ways to manipulate this as a string and obtain the three digits in the exponent. What I was interested in is to avoid string manipulation since the second example in my post shows that Python natively uses three digits in some case. Still not sure why it does so, as you have also asked above. I merely found it while experimenting. – nmadzharov Apr 02 '12 at 18:38
  • @nmadzharov I don't think there are any public function for that, you should try looking into python code to see what it is actually doing, though I don't see 3 digits in exponent on python 2.7 – Anurag Uniyal Apr 02 '12 at 19:44
  • @Anurag: three-digit exponents did appear on some platforms for Python 2.5; this was fixed in Python 2.6 (I believe). See http://bugs.python.org/issue1600 for more. – Mark Dickinson Apr 13 '12 at 07:08
  • 3
    I'm sad that this answer is correct, sure would be nice if you could specify the number of digits... almost downvoted... – foobarbecue Feb 12 '14 at 04:12
20

You can use np.format_float_scientific

from numpy import format_float_scientific

f = 0.0000870927939438012

format_float_scientific(f, exp_digits=3) # prints '8.70927939438012e-005'

format_float_scientific(f, exp_digits=5, precision=2) #prints '8.71e-00005'
Khalil Al Hooti
  • 4,207
  • 5
  • 23
  • 40
0

Here is a slightly more flexible answer (does either 'e' or 'E' to separate mantissa and exponent, is forgiving of missing/bad arguments). But I am upvoting the answer from @AnuragUniyal because that answer is so compact.

def efmte(x, n=6, m=2, e='e', nmax=16):
    def _expc(s): # return exponent character of e-formatted float
        return next(filter(lambda character: character in {'E', 'e'}, s))
    def _pad0(s, n): # return string padded to length n
        return ('{0:0>' + str(n) + '}').format(s)
    def _efmtes(s, n): # reformat e-formatted float: n e-digits
        m, e, p = s.partition(_expc(s)) # mantissa, exponent, +/-power
        return m + e + p[0] + _pad0(p[1:], n)
    def _efmt(x, n, e): # returns formatted float x: n decimals, 'e'/'E'
        return ('{0:.' + str(n) + e + '}').format(x)
    x = x if isinstance(x, float) else float('nan')
    nmax = 16 if not isinstance(nmax, int) else max(0, nmax)
    n = 6 if not isinstance(n, int) else min(max(0, n), nmax)
    m = 2 if not isinstance(m, int) else max(0, m)
    e = 'e' if e not in {'E', 'e'} else e
    return _efmtes(_efmt(x, n, e), m)

Examples:

>>> efmte(42., n=1, m=5)
'4.2e+00001'
>>> efmte('a')
'-1.#IND00e+00'
>>> # Yuck: I was expecting 'nan'. Anyone else?
>>> from math import pi
>>> efmte(pi)
'3.141593e+00'
>>> efmte(pi, m=3)
'3.141593e+000'
Ana Nimbus
  • 635
  • 3
  • 16
0

Similar to @Anurag Uniyal answer, but optionally removing the sign in the exponent (useful if one is tight in space).

def expformat(f, prec, exp_digits, sign='on'):
    """Scientific-format a number with a given number of digits in the exponent.
    Optionally remove the sign in the exponent"""
    s = "%.*e"%(prec, f)
    mantissa, exp = s.split('e')
    if (sign=='on') :
        # add 1 to digits as 1 is taken by sign +/-
        return "%se%+0*d"%(mantissa, exp_digits+1, int(exp))
    else :
        return "%se%0*d"%(mantissa, exp_digits, int(exp))