Skip to content

Commit 195ccdc

Browse files
author
Tech Lead Agent
committed
intword: name every short-scale power up to googol (fixes the decillion gap)
Values between 10**36 and a googol used to render as enormous decillion counts (e.g. intword(10**50) -> '100000000000000000.0 decillion'), and a value just below a googol never carried to '1.0 googol'. Extending powers/human_powers with the standard short-scale names for 10**36-10**99 (undecillion through duotrigintillion) gives every magnitude a unit and lets the existing integer-ratio carry fire across the final 10**99 -> 10**100 step as well. Upstream issue: #356
1 parent 392aef7 commit 195ccdc

2 files changed

Lines changed: 78 additions & 11 deletions

File tree

‎src/humanize/number.py‎

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,45 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str:
203203
return result
204204

205205

206-
powers = [10**x for x in (3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 100)]
206+
powers = [
207+
10**x
208+
for x in (
209+
3,
210+
6,
211+
9,
212+
12,
213+
15,
214+
18,
215+
21,
216+
24,
217+
27,
218+
30,
219+
33,
220+
36,
221+
39,
222+
42,
223+
45,
224+
48,
225+
51,
226+
54,
227+
57,
228+
60,
229+
63,
230+
66,
231+
69,
232+
72,
233+
75,
234+
78,
235+
81,
236+
84,
237+
87,
238+
90,
239+
93,
240+
96,
241+
99,
242+
100,
243+
)
244+
]
207245
human_powers = (
208246
NS_("thousand", "thousand"),
209247
NS_("million", "million"),
@@ -216,6 +254,28 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str:
216254
NS_("octillion", "octillion"),
217255
NS_("nonillion", "nonillion"),
218256
NS_("decillion", "decillion"),
257+
NS_("undecillion", "undecillion"),
258+
NS_("duodecillion", "duodecillion"),
259+
NS_("tredecillion", "tredecillion"),
260+
NS_("quattuordecillion", "quattuordecillion"),
261+
NS_("quindecillion", "quindecillion"),
262+
NS_("sexdecillion", "sexdecillion"),
263+
NS_("septendecillion", "septendecillion"),
264+
NS_("octodecillion", "octodecillion"),
265+
NS_("novemdecillion", "novemdecillion"),
266+
NS_("vigintillion", "vigintillion"),
267+
NS_("unvigintillion", "unvigintillion"),
268+
NS_("duovigintillion", "duovigintillion"),
269+
NS_("trevigintillion", "trevigintillion"),
270+
NS_("quattuorvigintillion", "quattuorvigintillion"),
271+
NS_("quinvigintillion", "quinvigintillion"),
272+
NS_("sexvigintillion", "sexvigintillion"),
273+
NS_("septenvigintillion", "septenvigintillion"),
274+
NS_("octovigintillion", "octovigintillion"),
275+
NS_("novemvigintillion", "novemvigintillion"),
276+
NS_("trigintillion", "trigintillion"),
277+
NS_("untrigintillion", "untrigintillion"),
278+
NS_("duotrigintillion", "duotrigintillion"),
219279
NS_("googol", "googol"),
220280
)
221281

@@ -225,7 +285,7 @@ def intword(value: NumberOrString, format: str = "%.1f") -> str:
225285
226286
Works best for numbers over 1 million. For example, 1_000_000 becomes "1.0 million",
227287
1_200_000 becomes "1.2 million" and "1_200_000_000" becomes "1.2 billion". Supports
228-
up to decillion (33 digits) and googol (100 digits).
288+
up to duotrigintillion (99 digits) and googol (100 digits).
229289
230290
Examples:
231291
```pycon

‎tests/test_number.py‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,12 @@ def test_intword_powers() -> None:
123123
(["3500000000000000000000"], "3.5 sextillion"),
124124
(["8100000000000000000000000000000000"], "8.1 decillion"),
125125
(["-8100000000000000000000000000000000"], "-8.1 decillion"),
126-
([1_000_000_000_000_000_000_000_000_000_000_000_000], "1000.0 decillion"),
127-
([1_100_000_000_000_000_000_000_000_000_000_000_000], "1100.0 decillion"),
128-
([2_100_000_000_000_000_000_000_000_000_000_000_000], "2100.0 decillion"),
126+
([1_000_000_000_000_000_000_000_000_000_000_000_000], "1.0 undecillion"),
127+
([1_100_000_000_000_000_000_000_000_000_000_000_000], "1.1 undecillion"),
128+
([2_100_000_000_000_000_000_000_000_000_000_000_000], "2.1 undecillion"),
129+
([10**50], "100.0 quindecillion"),
130+
([10**99], "1.0 duotrigintillion"),
131+
([10**100 - 10**93], "1.0 googol"),
129132
([2e100], "2.0 googol"),
130133
([None], "None"),
131134
(["1230000", "%0.2f"], "1.23 million"),
@@ -176,16 +179,20 @@ def test_intword_rounding_rollover() -> None:
176179
assert humanize.intword(value) == f"1.0 {units[i]}"
177180
assert humanize.intword(value, "%.0f") == f"1 {units[i]}"
178181

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

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

191198

0 commit comments

Comments
 (0)