Skip to content

Commit

Permalink
Fix uint64 conversion
Browse files Browse the repository at this point in the history
Stop using logarithm to compute the number of components.
Instead, use the theoretical maximum number of components for buffer,
and count up the actual number of components during conversion.
  • Loading branch information
mrkn committed Feb 4, 2021
1 parent 7479923 commit 9067b35
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 12 deletions.
23 changes: 11 additions & 12 deletions ext/bigdecimal/bigdecimal.c
Expand Up @@ -2727,23 +2727,22 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
vp->frac[0] = (DECDIG)uval;
}
else {
const size_t len = (size_t)ceil(log10((double)uval) / BASE_FIG);

vp = VpAllocReal(len);
vp->MaxPrec = len;
vp->Prec = len;
vp->exponent = len;
VpSetSign(vp, 1);

size_t i, ntz = 0;
for (i = 0; i < len; ++i) {
DECDIG buf[BIGDECIMAL_INT64_MAX_LENGTH] = {0,};
size_t exp = 0, ntz = 0;
for (; uval > 0; ++exp) {
DECDIG r = uval % BASE;
vp->frac[len - i - 1] = r;
if (r == 0) ++ntz;
buf[BIGDECIMAL_INT64_MAX_LENGTH - exp - 1] = r;
uval /= BASE;
}

vp->Prec -= ntz;
const size_t len = exp - ntz;
vp = VpAllocReal(len);
vp->MaxPrec = len;
vp->Prec = len;
vp->exponent = exp;
VpSetSign(vp, 1);
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - exp, DECDIG, len);
}

return BigDecimal_wrap_struct(obj, vp);
Expand Down
16 changes: 16 additions & 0 deletions ext/bigdecimal/bigdecimal.h
Expand Up @@ -54,9 +54,25 @@
#if SIZEOF_DECDIG == 4
# define BIGDECIMAL_BASE ((DECDIG)1000000000U)
# define BIGDECIMAL_COMPONENT_FIGURES 9
/*
* The number of components required for a 64-bit integer.
*
* INT64_MAX: 9_223372036_854775807
* UINT64_MAX: 18_446744073_709551615
*/
# define BIGDECIMAL_INT64_MAX_LENGTH 3

#elif SIZEOF_DECDIG == 2
# define BIGDECIMAL_BASE ((DECDIG)10000U)
# define BIGDECIMAL_COMPONENT_FIGURES 4
/*
* The number of components required for a 64-bit integer.
*
* INT64_MAX: 922_3372_0368_5477_5807
* UINT64_MAX: 1844_6744_0737_0955_1615
*/
# define BIGDECIMAL_INT64_MAX_LENGTH 5

#else
# error Unknown size of DECDIG
#endif
Expand Down

0 comments on commit 9067b35

Please sign in to comment.