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
22 changes: 21 additions & 1 deletion src/humanize/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,27 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str:
if not math.isfinite(float(value)):
return _format_not_finite(float(value))
if "." in value:
value = float(value)
# Without an explicit rounding request, grouping a decimal
# string must not lose digits to binary float rounding
# (issue #496: '1234567890123456.78' became '...456.8').
# Parse plain decimal strings exactly, as the Decimal input
# path already does; anything else (exponents, trailing
# dots) keeps the previous float behaviour.
parts = value.lstrip("+-").split(".")
digits = "0123456789"
if (
ndigits is None
and len(parts) == 2
and all(c in digits for c in parts[0])
and parts[0]
and all(c in digits for c in parts[1])
and parts[1]
):
from decimal import Decimal

value = Decimal(value)
else:
value = float(value)
else:
value = int(value)
elif not isinstance(value, int):
Expand Down
5 changes: 5 additions & 0 deletions tests/test_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ def test_ordinal(test_input: str, expected: str) -> None:
(["10311"], "10,311"),
(["1000000"], "1,000,000"),
(["1234567.1234567"], "1,234,567.1234567"),
# Regression for issue #496: grouping a large decimal string must
# not lose digits to binary float rounding.
(["1234567890123456.78"], "1,234,567,890,123,456.78"),
(["-1234567890123456.78"], "-1,234,567,890,123,456.78"),
(["14308.40"], "14,308.40"),
(["1234567.1234567", 0], "1,234,567"),
(["1234567.1234567", 1], "1,234,567.1"),
(["1234567.1234567", 10], "1,234,567.1234567000"),
Expand Down