Skip to content

Fix intword() rounding carry for very large numbers - #346

Merged
hugovk merged 1 commit into
python-humanize:mainfrom
binggao1230:fix-intword-carry-rollover
Sep 16, 2026
Merged

hugovk merged 1 commit into
python-humanize:mainfrom
binggao1230:fix-intword-carry-rollover

Conversation

@binggao1230

Copy link
Copy Markdown
Contributor

Problem

intword() decides whether rounding pushed a value up into the next magnitude
with:

if not largest_ordinal and rounded_value * power == powers[ordinal + 1]:

For values above ~10**22, rounded_value * power is evaluated in floating
point and no longer equals the exact powers[ordinal + 1], so the carry is
skipped and the number is rendered against the lower magnitude:

>>> import humanize
>>> humanize.intword(10**24 - 1)
'1000.0 sextillion'      # expected '1.0 septillion'
>>> humanize.intword(10**27 - 1)
'1000.0 septillion'      # expected '1.0 octillion'

The same happens at 10**30 and 10**33.

Fix

Compare rounded_value against the exact integer ratio
powers[ordinal + 1] // power, keeping the check in exact integer terms rather
than relying on a large float product. This mirrors the recently fixed carry
handling in metric() (#328) and naturalsize() (#329).

Tests

test_intword_rounding_rollover asserts the correct roll-over across every
affected magnitude (10**24/27/30/33 - 1), plus a couple of just-below cases
that must not roll over, guarding both directions.

pytest → 716 passed. ruff check / ruff format --check clean.

intword() detected the post-rounding carry into the next magnitude with
'rounded_value * power == powers[ordinal + 1]'. Above ~10**22 that product
is evaluated in floating point and no longer equals the exact next power, so
the carry was skipped and the value was rendered against the lower magnitude:
intword(10**24 - 1) returned '1000.0 sextillion' instead of '1.0 septillion'
(same for 10**27, 10**30, 10**33).

Compare rounded_value against the exact integer ratio powers[ordinal+1] // power
instead, keeping the comparison in exact integer/short-float terms. This mirrors
the recently fixed carry handling in metric() (python-humanize#328) and naturalsize() (python-humanize#329).
@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.56%. Comparing base (4c85c35) to head (eda405b).
⚠️ Report is 21 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #346   +/-   ##
=======================================
  Coverage   99.56%   99.56%           
=======================================
  Files          12       12           
  Lines         913      925   +12     
=======================================
+ Hits          909      921   +12     
  Misses          4        4           
Flag Coverage Δ
macos-latest 97.62% <100.00%> (+0.03%) ⬆️
ubuntu-latest 97.62% <100.00%> (+0.03%) ⬆️
windows-latest 95.78% <100.00%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codspeed

codspeed Bot commented Jul 6, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 15 untouched benchmarks


Comparing gaoflow:fix-intword-carry-rollover (eda405b) with main (4c85c35)

Open in CodSpeed

@hugovk hugovk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import humanize

print(humanize.intword(10**24 - 1))
print(humanize.intword(10**33 - 1))
print(humanize.intword(-(10**24 - 1)))
print(humanize.intword(10**24 - 1, "%.0f"))

Before

1000.0 sextillion
1000.0 nonillion
-1000.0 sextillion
1000 sextillion

After

1.0 septillion
1.0 decillion
-1.0 septillion
1 septillion

@hugovk hugovk changed the title Fix intword() rounding carry for very large numbers Fix intword() rounding carry for very large numbers Sep 16, 2026
@hugovk
hugovk merged commit ca892b3 into python-humanize:main Sep 16, 2026
43 of 44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog: Fixed For any bug fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants