[ruby/bigdecimal] Fix uint64 conversion

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.

https://github.com/ruby/bigdecimal/commit/9067b353ac
This commit is contained in:
Kenta Murata 2021-01-30 13:00:03 +09:00
parent 868d66e0b5
commit 4e2e1d6093
No known key found for this signature in database
GPG Key ID: CEFE8AFB6081B062
2 changed files with 27 additions and 12 deletions

View File

@ -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);

View File

@ -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