mini-gmp and mpq

Marco Bodrato bodrato at mail.dm.unipi.it
Sun May 6 16:48:40 UTC 2018


Ciao,

I reply to an e-mail from gmp-discuss.

Il Lun, 19 Febbraio 2018 5:24 pm, Marc Glisse ha scritto:
> On Mon, 19 Feb 2018, Marco Bodrato wrote:
>> Il Mer, 14 Febbraio 2018 8:07 pm, Andreas Fabri ha scritto:
>>> 2) the conversion of a mpq to its closest double
>>
>> mpq_get_d currently gives a double, but rounded towards zero...
>
> Except when it uses the broken generic code :-(

Maybe things get better if we mask a fixed number of bits during conversion?

A possible patch (to mpn/generic/get_d.c) follows:

diff -r 110bcd4c29f4 mpn/generic/get_d.c
--- a/mpn/generic/get_d.c       Sun May 06 08:48:36 2018 +0200
+++ b/mpn/generic/get_d.c       Sun May 06 18:28:20 2018 +0200
@@ -32,6 +32,12 @@
 GNU Lesser General Public License along with the GNU MP Library.  If not,
 see https://www.gnu.org/licenses/.  */

+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MANT_DIG and FLT_RADIX */
+#endif
+
 #include "gmp-impl.h"
 #include "longlong.h"

@@ -354,7 +360,20 @@
 #endif

 #if ! FORMAT_RECOGNIZED
-    {      /* Non-IEEE or strange limb size, do something generic. */
+
+#if !defined(GMP_DBL_MANT_BITS)
+#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
+#define GMP_DBL_MANT_BITS DBL_MANT_DIG
+#else
+/* FIXME: Chose a smarter default value. */
+#define GMP_DBL_MANT_BITS (16 * sizeof (double))
+#endif
+#endif
+
+    { /* Non-IEEE or strange limb size, generically convert
+        GMP_DBL_MANT_BITS bits. */
+      mp_limb_t l;
+      int m;
       mp_size_t i;
       double d, weight;
       unsigned long uexp;
@@ -366,13 +385,21 @@
         limbs.  */
-      weight = 1/MP_BASE_AS_DOUBLE;
-      d = up[size - 1];
-      for (i = size - 2; i >= 0; i--)
-       {
-         d += up[i] * weight;
-         weight /= MP_BASE_AS_DOUBLE;
-         if (weight == 0)
-           break;
-       }
+      i = size - 1;
+      l = up[i];
+      count_leading_zeros (m, l);
+      m = m - GMP_LIMB_BITS + GMP_DBL_MANT_BITS;
+      if (m < 0)
+       l &= GMP_NUMB_MAX << -m;
+      d = l;
+      for (weight = 1/MP_BASE_AS_DOUBLE; m > 0 && --i >= 0;) {
+       l = up[i];
+       m -= GMP_NUMB_BITS;
+       if (m < 0)
+         l &= GMP_NUMB_MAX << -m;
+       d += l * weight;
+       weight /= MP_BASE_AS_DOUBLE;
+       if (weight == 0)
+         break;
+      }

       /* Now apply exp.  */
       exp -= GMP_NUMB_BITS;


The large default value for GMP_DBL_MANT_BITS should give us basically the
same behaviour as the current code, in the worst case.

Ĝis,
m

-- 
http://bodrato.it/papers/



More information about the gmp-devel mailing list