Bill Allombert on Wed, 03 Aug 2005 11:11:34 +0200


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

faster output with the GMP kernel


Hello PARI-dev,

Here a patch that add a function conv_with_gmp that can be used
in place of convi for faster output of large integers and reals
when the GMP kernel is in use.
(You have to manually tweak convi to call convi_with_gmp).

You have to use 'time' for timing it since the GP timer does not
take into account the output time:

(using the GMP kernel:)

Without the patch: 16.83s

%time echo "3^400000" | ./gp -q -f>/dev/null
echo "3^400000"  0,00s user 0,01s system 27% cpu 0,036 total
./gp -q -f > /dev/null  16,83s user 0,03s system 100% cpu 16,828 total

With the patch: 2.25s

%time echo "3^400000" | ./gp -q -f>/dev/null
echo "3^400000"  0,00s user 0,01s system 26% cpu 0,037 total
./gp -q -f > /dev/null  2,25s user 0,04s system 100% cpu 2,276 total

This patch is messy since it has to convert between GMP and PARI
packed decimals format.

We should extend the kernel to cover binary to decimal conversion
(and eventually others bases) but it would be better if it was 
independant on the choice of a decimal packing format. The hard part
is to support formatted real output (which require fiddling with decimal
digits).

Cheers,
Bill

Index: pari/src/kernel/gmp/mp.c
===================================================================
--- pari.orig/src/kernel/gmp/mp.c	2005-08-02 22:56:31.000000000 +0200
+++ pari/src/kernel/gmp/mp.c	2005-08-02 23:40:38.000000000 +0200
@@ -1239,3 +1239,39 @@
     if (x[i]) { setlgefint(x, i+1); return x; }
   x[1] = evalsigne(0) | evallgefint(2); return x;
 }
+
+/*******************************************************************
+ *                           base conversion                       *
+ *******************************************************************/
+
+ulong *convi_with_gmp(GEN x, long *l)
+{
+  long n = nchar2nlong(2 + (long)(NLIMBS(x) * (BITS_IN_LONG / L2SL10)));
+  GEN str = cgetg(n+1, t_VECSMALL);
+  unsigned char *t = GSTR(str);
+  long llz = mpn_get_str(t, 10, LIMBS(icopy(x)), NLIMBS(x));
+  long lz  = (8+llz)/9; 
+  ulong *z = (ulong*)new_chunk(1+lz);
+  long i, j;
+  t+=llz+9;
+  for(i=0;i<llz-8;i+=9)
+  {
+    ulong s;
+    t-=18;
+    s=*t++;
+    for (j=1; j<9;j++)
+      s=10*s+*t++;
+    *z++=s;
+  }
+  if (i<llz)
+  {
+    ulong s;
+    t=GSTR(str);
+    s=*t++;
+    for (j=i+1; j<llz;j++)
+      s=10*s+*t++;
+    *z++=s;
+  }
+  *l = lz;
+  return z;
+}