diff --git a/src/humanize/number.py b/src/humanize/number.py index 52a5356a..3956c346 100644 --- a/src/humanize/number.py +++ b/src/humanize/number.py @@ -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"), @@ -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"), ) @@ -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 diff --git a/tests/test_number.py b/tests/test_number.py index 5fb12fa6..6b532da1 100644 --- a/tests/test_number.py +++ b/tests/test_number.py @@ -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"), @@ -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"