Problem with large values in GMP...
wraithx at morpheus.net
wraithx at morpheus.net
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 gmp-h.in 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-h.in gmp-h.in
--- ../gmp-6.1.0.orig/gmp-h.in 2015-11-01 09:19:48.000000000 -0600
+++ gmp-h.in 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;
#else
#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;
#else
typedef unsigned long int mp_limb_t;
typedef long int mp_limb_signed_t;
+typedef unsigned long int mp_bitcnt_t;
#endif
#endif
-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;
#else
#define __GMP_MP_SIZE_T_INT 0
+#ifdef _LONG_LONG_LIMB
+typedef long long int mp_size_t;
+typedef long long int mp_exp_t;
+#else
typedef long int mp_size_t;
typedef long int mp_exp_t;
#endif
+#endif
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