diff options
-rw-r--r-- | ext/bigdecimal/bigdecimal.c | 23 | ||||
-rw-r--r-- | ext/bigdecimal/bigdecimal.h | 16 |
2 files changed, 27 insertions, 12 deletions
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index b9ba0ea62d..704f04510e 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -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); diff --git a/ext/bigdecimal/bigdecimal.h b/ext/bigdecimal/bigdecimal.h index acc00b8127..bd1c46743e 100644 --- a/ext/bigdecimal/bigdecimal.h +++ b/ext/bigdecimal/bigdecimal.h @@ -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 |