Skip to content
Open
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
62 changes: 60 additions & 2 deletions src/humanize/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,44 @@ 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,
100,
)
]
human_powers = (
NS_("thousand", "thousand"),
NS_("million", "million"),
Expand All @@ -216,6 +253,27 @@ 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_("googol", "googol"),
)

Expand All @@ -225,7 +283,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 untrigintillion (96 digits) and googol (100 digits).

Examples:
```pycon
Expand Down
29 changes: 24 additions & 5 deletions tests/test_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ 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"),
([2e100], "2.0 googol"),
([None], "None"),
(["1230000", "%0.2f"], "1.23 million"),
Expand Down Expand Up @@ -184,8 +184,8 @@ def test_intword_rounding_rollover() -> None:
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"
# Extended number names now cover undecillion through vigintillion.
assert humanize.intword(10**36) == "1.0 undecillion"
assert humanize.intword(2 * 10**100) == "2.0 googol"


Expand Down Expand Up @@ -377,3 +377,22 @@ def test_clamp(test_args: list[typing.Any], expected: str) -> None:
)
def test_metric(test_args: list[typing.Any], expected: str) -> None:
assert humanize.metric(*test_args) == expected


def test_intword_extended_number_names() -> None:
assert humanize.intword(10**36) == "1.0 undecillion"
assert humanize.intword(10**39) == "1.0 duodecillion"
assert humanize.intword(-(10**36)) == "-1.0 undecillion"
assert humanize.intword(10**36, "%.2f") == "1.00 undecillion"
assert humanize.intword(10**66) == "1.0 unvigintillion"
assert humanize.intword(10**69) == "1.0 duovigintillion"
assert humanize.intword(10**72) == "1.0 trevigintillion"
assert humanize.intword(10**75) == "1.0 quattuorvigintillion"
assert humanize.intword(10**78) == "1.0 quinvigintillion"
assert humanize.intword(10**81) == "1.0 sexvigintillion"
assert humanize.intword(10**84) == "1.0 septenvigintillion"
assert humanize.intword(10**87) == "1.0 octovigintillion"
assert humanize.intword(10**90) == "1.0 novemvigintillion"
assert humanize.intword(10**93) == "1.0 trigintillion"
assert humanize.intword(10**96) == "1.0 untrigintillion"
assert humanize.intword(10**100) == "1.0 googol"