Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions src/humanize/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,45 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str:
return result


powers = [10**x for x in (3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 100)]
powers = [
10**x
for x in (
3,
6,
9,
12,
15,
18,
21,
24,
27,
30,
33,
36,
39,
42,
45,
48,
51,
54,
57,
60,
63,
66,
69,
72,
75,
78,
81,
84,
87,
90,
93,
96,
99,
100,
)
]
human_powers = (
NS_("thousand", "thousand"),
NS_("million", "million"),
Expand All @@ -216,6 +254,28 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str:
NS_("octillion", "octillion"),
NS_("nonillion", "nonillion"),
NS_("decillion", "decillion"),
NS_("undecillion", "undecillion"),
NS_("duodecillion", "duodecillion"),
NS_("tredecillion", "tredecillion"),
NS_("quattuordecillion", "quattuordecillion"),
NS_("quindecillion", "quindecillion"),
NS_("sexdecillion", "sexdecillion"),
NS_("septendecillion", "septendecillion"),
NS_("octodecillion", "octodecillion"),
NS_("novemdecillion", "novemdecillion"),
NS_("vigintillion", "vigintillion"),
NS_("unvigintillion", "unvigintillion"),
NS_("duovigintillion", "duovigintillion"),
NS_("trevigintillion", "trevigintillion"),
NS_("quattuorvigintillion", "quattuorvigintillion"),
NS_("quinvigintillion", "quinvigintillion"),
NS_("sexvigintillion", "sexvigintillion"),
NS_("septenvigintillion", "septenvigintillion"),
NS_("octovigintillion", "octovigintillion"),
NS_("novemvigintillion", "novemvigintillion"),
NS_("trigintillion", "trigintillion"),
NS_("untrigintillion", "untrigintillion"),
NS_("duotrigintillion", "duotrigintillion"),
NS_("googol", "googol"),
)

Expand All @@ -225,7 +285,7 @@ def intword(value: NumberOrString, format: str = "%.1f") -> str:

Works best for numbers over 1 million. For example, 1_000_000 becomes "1.0 million",
1_200_000 becomes "1.2 million" and "1_200_000_000" becomes "1.2 billion". Supports
up to decillion (33 digits) and googol (100 digits).
up to duotrigintillion (99 digits) and googol (100 digits).

Examples:
```pycon
Expand Down
25 changes: 16 additions & 9 deletions tests/test_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,12 @@ def test_intword_powers() -> None:
(["3500000000000000000000"], "3.5 sextillion"),
(["8100000000000000000000000000000000"], "8.1 decillion"),
(["-8100000000000000000000000000000000"], "-8.1 decillion"),
([1_000_000_000_000_000_000_000_000_000_000_000_000], "1000.0 decillion"),
([1_100_000_000_000_000_000_000_000_000_000_000_000], "1100.0 decillion"),
([2_100_000_000_000_000_000_000_000_000_000_000_000], "2100.0 decillion"),
([1_000_000_000_000_000_000_000_000_000_000_000_000], "1.0 undecillion"),
([1_100_000_000_000_000_000_000_000_000_000_000_000], "1.1 undecillion"),
([2_100_000_000_000_000_000_000_000_000_000_000_000], "2.1 undecillion"),
([10**50], "100.0 quindecillion"),
([10**99], "1.0 duotrigintillion"),
([10**100 - 10**93], "1.0 googol"),
([2e100], "2.0 googol"),
([None], "None"),
(["1230000", "%0.2f"], "1.23 million"),
Expand Down Expand Up @@ -176,16 +179,20 @@ def test_intword_rounding_rollover() -> None:
assert humanize.intword(value) == f"1.0 {units[i]}"
assert humanize.intword(value, "%.0f") == f"1 {units[i]}"

# The mantissa must never render at or above 1000 for values below a
# decillion; a bare "1000.0" is only expected in the sparse gap between
# decillion and googol, which has no dedicated unit.
for exponent in range(6, 34, 3):
# The mantissa must never render at or above 1000: every magnitude up to
# duotrigintillion (10**99) has a dedicated unit, and just below a googol
# the value carries to "1.0 googol".
for exponent in range(6, 100, 3):
rendered = humanize.intword(10**exponent - 1)
mantissa = float(rendered.split(" ", 1)[0])
assert mantissa < 1000

# The documented decillion..googol gap must be left untouched.
assert humanize.intword(10**36) == "1000.0 decillion"
# The former decillion..googol gap is now named (#356): the magnitudes
# that used to render as huge decillion counts carry the correct unit.
assert humanize.intword(10**36) == "1.0 undecillion"
assert humanize.intword(10**50) == "100.0 quindecillion"
assert humanize.intword(10**99) == "1.0 duotrigintillion"
assert humanize.intword(10**100 - 10**93) == "1.0 googol"
assert humanize.intword(2 * 10**100) == "2.0 googol"


Expand Down