Problem with large values in GMP...

wraithx at wraithx at
Thu Mar 24 04:02:22 UTC 2016

On 3/19/2016 6:21 AM, Torbjörn Granlund wrote:
> I believe it to be possible to make LP64 and LLP64 systems work mostly
> equally well with GMP, but not within the current compatibility
> promises.
> We use our own type for sizes, mp_size_t, which unlike size_t is signed,
> and also unlike size_t will not automatically follow the size of
> pointers; it is never declared as anything greater than `long'.
> So mp_bitcnt_t and mp_size_t would need to be defined as 'long long'
> types, and then the result would need to be tested on a LLP64 system
> with lots of RAM.

I have created a test version of GMP where I only had to change two files.  I 
changed and tested it on my Win64 computer.  I ran into one error with 
tests/mpz/t-io_raw.c and had to make a change to mpz/inp_raw.c.  After changing 
these two files, I was able to successfully run configure, make, and "make 
check" on my Win64 computer.  I also tested these two changed files on a Linux64 
computer.  This too ran configure, make, and "make check" successfully.  I also 
tested the resulting gmp.h/libgmp.a files with GMP-ECM and that successfully 
completed configure, make, and "make check" on both systems.

I know my change for inp_raw.c may not work for all systems supported by GMP, 
but I wanted to share my change in hopes that a solution for all systems would 
be easy for you all to find.  The reason behind the line: "csize = (int)csize;" 
is because csize_bytes[4] is only 4 bytes long.  And since int is (usually) 4 
bytes long, this takes care of sign extending the value in csize, regardless of 
the size of csize.  Perhaps this change can be conditional with #ifdef's to use 
the original code on systems that need it.

Below is the diff between the official 6.1.0 and my experimental version.  I'd 
be very interested to hear how this works on any test systems you may try this 
out on.

-David C.

P.S.  I tested Rob's program where each number had 4e9 bits, and the program 
produced the correct output:
mpz_mul(num3, num1, num2)
num bits in num1 = 4000000000
num bits in num2 = 4000000000
num bits in num3 = 8000000000


[gmp-6.1.0.experimental]$ diff -u ../gmp-6.1.0.orig/
--- ../gmp-6.1.0.orig/	2015-11-01 09:19:48.000000000 -0600
+++	2016-03-23 22:10:23.305022216 -0500
@@ -136,16 +136,18 @@
  #ifdef __GMP_SHORT_LIMB
  typedef unsigned int		mp_limb_t;
  typedef int			mp_limb_signed_t;
+typedef unsigned int	mp_bitcnt_t;
  #ifdef _LONG_LONG_LIMB
  typedef unsigned long long int	mp_limb_t;
  typedef long long int		mp_limb_signed_t;
+typedef unsigned long long int	mp_bitcnt_t;
  typedef unsigned long int	mp_limb_t;
  typedef long int		mp_limb_signed_t;
+typedef unsigned long int	mp_bitcnt_t;
-typedef unsigned long int	mp_bitcnt_t;

  /* For reference, note that the name __mpz_struct gets into C++ mangled
     function names, which means although the "__" suggests an internal, we
@@ -175,9 +177,14 @@
  typedef int			mp_exp_t;
  #define __GMP_MP_SIZE_T_INT     0
+typedef long long int		mp_size_t;
+typedef long long int		mp_exp_t;
  typedef long int		mp_size_t;
  typedef long int		mp_exp_t;

  typedef struct


[gmp-6.1.0.experimental]$ diff -u ../gmp-6.1.0.orig/mpz/inp_raw.c mpz/inp_raw.c
--- ../gmp-6.1.0.orig/mpz/inp_raw.c	2015-11-01 09:19:49.000000000 -0600
+++ mpz/inp_raw.c	2016-03-23 22:03:39.266026463 -0500
@@ -87,8 +87,9 @@
    /* Sign extend if necessary.
       Could write "csize -= ((csize & 0x80000000L) << 1)", but that tickles a
       bug in gcc 3.0 for powerpc64 on AIX.  */
-  if (sizeof (csize) > 4 && csize & 0x80000000L)
-    csize -= 0x80000000L << 1;
+  //if (sizeof (csize) > 4 && csize & 0x80000000L)
+  //  csize -= 0x80000000L << 1;
+  csize = (int)csize;

    abs_csize = ABS (csize);

More information about the gmp-discuss mailing list