Skip to content

Commit 101c869

Browse files
vidigoathugovk
authored andcommitted
Fix metric() showing an extra significant digit on rounding carry
metric() derives the number of decimal places from the mantissa's exponent, assuming the mantissa keeps its digit count. When rounding carries it up a power of ten (9.999 -> 10.0, 99.99 -> 100) it gains an integer digit and shows one significant figure too many, e.g. metric(9999) returned '10.00 k' instead of '10.0 k'. The existing guard only handled the mantissa reaching 1000 (a full SI-bucket crossing). Detect the carry against the next power of ten and bump the exponent by one, which recomputes the decimal places and, when the mantissa reaches 1000, still crosses into the next bucket exactly as before.
1 parent 984526c commit 101c869

2 files changed

Lines changed: 16 additions & 2 deletions

File tree

src/humanize/number.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -550,8 +550,13 @@ def metric(value: float, unit: str = "", precision: int = 3) -> str:
550550
old_bucket = exponent // 3 * 3
551551
value /= 10**old_bucket
552552
digits = int(max(0, precision - exponent % 3 - 1))
553-
if exponent < 30 and round(abs(value), digits) >= 1000:
554-
exponent += 3 - exponent % 3
553+
# Rounding to ``digits`` decimal places can carry the mantissa up to the
554+
# next power of ten (e.g. 9.999 -> 10.0, 99.99 -> 100, 999.9 -> 1000),
555+
# which adds an integer digit and would otherwise show one significant
556+
# figure too many. Bump the exponent to absorb the carry -- crossing into
557+
# the next SI bucket when the mantissa reaches 1000 -- and recompute.
558+
if exponent < 30 and round(abs(value), digits) >= 10 ** (exponent % 3 + 1):
559+
exponent += 1
555560
new_bucket = exponent // 3 * 3
556561
value /= 10 ** (new_bucket - old_bucket)
557562
digits = int(max(0, precision - exponent % 3 - 1))

tests/test_number.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,15 @@ def test_clamp(test_args: list[typing.Any], expected: str) -> None:
270270
([1234.56], "1.23 k"),
271271
([12345, "", 6], "12.3450 k"),
272272
([200_000], "200 k"),
273+
# Rounding that carries the mantissa up a power of ten within a
274+
# bucket must not add an extra significant figure (issue: metric
275+
# showed one digit too many for e.g. 9999 -> "10.00 k").
276+
([9999], "10.0 k"),
277+
([99999], "100 k"),
278+
([9.99999], "10.0"),
279+
([-9999], "-10.0 k"),
280+
([9.999, "", 2], "10"),
281+
([999.4], "999"),
273282
([999.9, "V"], "1.00 kV"),
274283
([999.99, "V"], "1.00 kV"),
275284
([999_999, "V"], "1.00 MV"),

0 commit comments

Comments
 (0)