Skip to content

fix: NumDigits underreports for some exact powers of ten#425

Open
c-tonneslan wants to merge 1 commit into
shopspring:masterfrom
c-tonneslan:fix/numdigits-log10-imprecision
Open

fix: NumDigits underreports for some exact powers of ten#425
c-tonneslan wants to merge 1 commit into
shopspring:masterfrom
c-tonneslan:fix/numdigits-log10-imprecision

Conversation

@c-tonneslan
Copy link
Copy Markdown

From the reporter in #420:

100000000000000E20:  ... 15 15   (ok: 15 digits)
1000000000000000E20: ... 16 15   (wrong: 16 digits, NumDigits says 15)
10000000000000000E20: ... 17 17  (ok: 17 digits)

The fast path returns int(math.Log10(math.Abs(float64(i64)))) + 1, and math.Log10 of an exact power of ten doesn't always round to the exact integer. On my machine:

log10(1e14) = 14.0
log10(1e15) = 14.99999999999999822364
log10(1e16) = 16.0

So 1e15 takes the wrong branch and int(...) + 1 returns 15 instead of 16. Same shape at 1e24, 1e28, and other powers where the float64 representation drifts down.

Count digits via plain int64 division instead. No floats, no estimate. The big.Int slow path is unchanged.

Regression cases added to TestDecimal_NumDigits cover 1e15 directly, with sign and scientific-notation variants, plus 1<<53 (the boundary of the old fast path). Fails on master, passes here. go test ./... is clean.

Fixes #420.

math.Log10(1eN) rounds down to N-1 for several N (15, 24, 28, ...)
because the exact decimal can't survive a float64 round-trip. The
fast path returned int(math.Log10(...)) + 1, so a coefficient like
1000000000000000 (16 digits) came back as 15.

Count digits via int64 division for the IsInt64 branch. The slow
big.Int path is unchanged.

Regression tests cover 1e15 and -1e15 (both via plain literal and
scientific-notation input) and 1<<53 (the old fast-path boundary).

Fixes shopspring#420

Signed-off-by: Charlie Tonneslan <cst0520@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decimal.NumDigits returns invalid value

1 participant