1

I found this which covers how to suppress scientific notation, but I'd like to go a step further and also work out the formatting string (i.e. the number of required decimal points to represent a number).

My idea so far is to assume a very high resolution (20 in this example) and reduce trailing zeroes as suggested in the accepted answer here. Is there perhaps a better way to achieve this?

>>> f = 0.00000008
>>> s = '{:.20f}'.format(f)
>>> s
'0.00000008000000000000'
>>> s.rstrip('0')
'0.00000008'

Note, I don't want scientific notation either (which you would get with a formatting string of {:g}).

Community
  • 1
  • 1
orange
  • 7,755
  • 14
  • 75
  • 139

1 Answers1

0

The max number of significant digits in a float is 15 (the power is separate from this). So there's no point in accounting for more digits past that, as they wouldn't be right. Knowing what the power of ten for a given number will tell you how many zeros to pad out in the front.

If what you're formatting will never get above one, then the following will suffice:

from math import log10

def floatformat(f):
    pwr = log10(f)
    return '{:.0{}f}'.format(f, int(abs(pwr)) + 15).rstrip('0')

But if you're parsing any possible float value, you'll have to handle large numbers a bit differently to get trailing zeros and not random inaccurate digits.

def floatformat(f):
    sigs = 15  # number of accurate digits that a float can contain
    pwr = log10(f)

    if pwr > sigs:  # power above accurate digits
         s = '{:.{}f}'.format(f / 10 ** int(pwr), sigs)
         s = s.replace('.', '')  # remove decimal point, no longer necessary here
         s = s + '0' * (int(pwr) - sigs)  # add in trailing zeros

    elif 0 < pwr <= sigs:  # power within accurate digits
        s = '{:.{}f}'.format(f, sigs - int(pwr)).rstrip('0')

    else:  # power below accurate digits
        s = '{:.0{}f}'.format(f, int(abs(pwr)) + sigs).rstrip('0')

    if s[-1] == '.': s = s[:-1]  # remove trailing decimal point if needed
    return s

All this is doing is keeping the accurate digits, then shuffling them around to have the correct power without the scientific notation.

Examples:

>>> floatformat(0.00000008)
'0.00000008'
>>> floatformat(0.0000000000000000000000000000008)
'0.0000000000000000000000000000008'
>>> floatformat(0.00000000000000000000000000000080067)
'0.00000000000000000000000000000080067'
>>> floatformat(2.31451103e7)
'23145110.3'
>>> floatformat(2.31451103e3)
'2314.51103'
>>> 935.16087e203 == float(floatformat(935.16087e203))  # conversion check to see if power is handled correctly
True
>>> import sys
>>> floatformat(sys.float_info.max)
'179769313486231600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
>>> floatformat(sys.float_info.min)
'0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072'
Status
  • 912
  • 1
  • 12
  • 23