[前][次][番号順一覧][スレッド一覧]

ruby-changes:65135

From: Kenta <ko1@a...>
Date: Thu, 4 Feb 2021 13:19:16 +0900 (JST)
Subject: [ruby-changes:65135] 4e2e1d6093 (master): [ruby/bigdecimal] Fix uint64 conversion

https://git.ruby-lang.org/ruby.git/commit/?id=4e2e1d6093

From 4e2e1d60936a3dcbc0e51b1c9c925ef41c1780f6 Mon Sep 17 00:00:00 2001
From: Kenta Murata <mrkn@m...>
Date: Sat, 30 Jan 2021 13:00:03 +0900
Subject: [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
---
 ext/bigdecimal/bigdecimal.c | 23 +++++++++++------------
 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 b9ba0ea..704f045 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 https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2727
         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 acc00b8..bd1c467 100644
--- a/ext/bigdecimal/bigdecimal.h
+++ b/ext/bigdecimal/bigdecimal.h
@@ -54,9 +54,25 @@ https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.h#L54
 #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
-- 
cgit v1.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]