55

is there a python library that would make numbers such as this more human readable

$187,280,840,422,780

edited: for example iw ant the output of this to be 187 Trillion not just comma separated. So I want output to be trillions, millions, billions etc

kevin
  • 4,177
  • 10
  • 32
  • 33
  • 1
    install clisp and write this: `(format t "~r" (parse-integer (read-line *standard-input*)))` then use subprocess to call `clisp prettynum.cl 187,000,000,000,000`... Though I just asked about an alternative http://stackoverflow.com/questions/3158132/is-there-a-python-version-of-lisps-format-r – Wayne Werner Jul 01 '10 at 13:20
  • [`python-ballpark`](https://github.com/debrouwere/python-ballpark) seems to be designed exactly for what the OP asks for. – 0 _ May 26 '17 at 21:03
  • Check out [millify](https://github.com/azaitsev/millify) – Alex Zaitsev Jan 16 '18 at 11:42
  • 1
    I obtain my desired effect (e.g., 11,232,222 to 11.23 M) using the millify package with one line of code `millify(the_number, precision=2)`. check https://github.com/azaitsev/millify. – YinchaoOnline Apr 05 '21 at 12:56
  • 1
    See also: [How to specify large integer literals in a readable way?](https://stackoverflow.com/a/73069015/967621) to input and output integers with underscores like so: `1_000_000`. – Timur Shtatland Jul 21 '22 at 15:35

5 Answers5

103

As I understand it, you only want the 'most significant' part. To do so, use floor(log10(abs(n))) to get number of digits and then go from there. Something like this, maybe:

import math

millnames = ['',' Thousand',' Million',' Billion',' Trillion']

def millify(n):
    n = float(n)
    millidx = max(0,min(len(millnames)-1,
                        int(math.floor(0 if n == 0 else math.log10(abs(n))/3))))

    return '{:.0f}{}'.format(n / 10**(3 * millidx), millnames[millidx])

Running the above function for a bunch of different numbers:

for n in (1.23456789 * 10**r for r in range(-2, 19, 1)):
    print('%20.1f: %20s' % (n,millify(n)))
                 0.0:                    0
                 0.1:                    0
                 1.2:                    1
                12.3:                   12
               123.5:                  123
              1234.6:           1 Thousand
             12345.7:          12 Thousand
            123456.8:         123 Thousand
           1234567.9:            1 Million
          12345678.9:           12 Million
         123456789.0:          123 Million
        1234567890.0:            1 Billion
       12345678900.0:           12 Billion
      123456789000.0:          123 Billion
     1234567890000.0:           1 Trillion
    12345678900000.0:          12 Trillion
   123456789000000.0:         123 Trillion
  1234567890000000.0:        1235 Trillion
 12345678899999998.0:       12346 Trillion
123456788999999984.0:      123457 Trillion
1234567890000000000.0:     1234568 Trillion
Janus
  • 5,421
  • 2
  • 26
  • 37
77

Note the question has changed over the years - please see Janus's response to get the "human" numbers or keep reading if you just want to format the number as a string with separators.

With Python2.7+ or v3 you just use the "," option in your string formatting - see PEP 378: Format Specifier for Thousands Separator for more info:

>>> "{:,}".format(100000000)
'100,000,000'

With Python3.6+ you can also use the "_" format - see PEP 515 for details:

>>> "{:_}".format(100000000)
'100_000_000'

or you can use a similar syntax with f-strings:

>>> number = 100000000
>>>f"{number:,}"
'100,000,000'

So I don't have to squint while reading big numbers, I have the 2.7 version of the code wrapped up in a shell function:

human_readable_numbers () {
    python2.7 -c "print('{:,}').format($1)"
}

Lastly, if for some reason you must work with code from Python versions 2.6 or earlier, you can solve the problem using the locale standard library module:

import locale
locale.setlocale(locale.LC_ALL, 'en_US')
locale.format('%d', 2**32, grouping=True)   # returns '4,294,967,296'
Lester Cheung
  • 1,964
  • 16
  • 17
  • 2
    What kind of syntax is `'{:,}'.format(x)`? I can try it out and see that it works, but I haven't seen that syntax before, so, how does it work? – HelloGoodbye Jun 16 '18 at 15:59
  • 5
    It's in PEP-0378: "The ',' option indicates that commas should be included in the output as a thousands separator. As with locales which do not use a period as the decimal point, locales which use a different convention for digit separation will need to use the locale module to obtain appropriate formatting." – Lester Cheung Jun 19 '18 at 03:04
  • 1
    Thank you Lester! – HelloGoodbye Jun 20 '18 at 08:58
  • 1
    The use of `,` and `_` for this purpose in format specifiers is also described [in the documentation for the format mini-language](https://docs.python.org/3/library/string.html#format-specification-mini-language). – Karl Knechtel Dec 10 '21 at 01:34
  • 1
    Add `.2f` for `.00` like this `print(f'{1_000:,.2f}')` – Muhammad Yasirroni Aug 19 '22 at 03:06
  • for responding to a 11 year old answer! ❤️ – Lester Cheung Aug 23 '22 at 01:04
4

That number seems pretty human-readable to me. An unfriendly number would be 187289840422780.00. To add commas, you could create your own function or search for one (I found this):

import re

def comma_me(amount):
    orig = amount
    new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', amount)
    if orig == new:
        return new
    else:
        return comma_me(new)

f = 12345678
print comma_me(`f`)
Output: 12,345,678

If you want to round a number to make it more readable, there is a python function for that: round().

You could move even further away from the actual data and say "A very high amount" or "Above 100 trillion" using a function that would return a different value based on your programmed benchmarks.

alecwh
  • 984
  • 2
  • 10
  • 17
1

From here:

def commify(n):
    if n is None: return None
    if type(n) is StringType:
        sepdec = localenv['mon_decimal_point']
    else:
        #if n is python float number we use everytime the dot
        sepdec = '.'
    n = str(n)
    if sepdec in n:
        dollars, cents = n.split(sepdec)
    else:
        dollars, cents = n, None

    r = []
    for i, c in enumerate(reversed(str(dollars))):
        if i and (not (i % 3)):
            r.insert(0, localenv['mon_thousands_sep'])
        r.insert(0, c)
    out = ''.join(r)
    if cents:
        out += localenv['mon_decimal_point'] + cents
    return out
Arkady
  • 14,305
  • 8
  • 42
  • 46
0

If by 'readable' you mean 'words'; here's a good solution that you can adapt.

http://www.andrew-hoyer.com/experiments/numbers

dagoof
  • 1,137
  • 11
  • 14