gmp_asprintf prints wrong exponents for sufficiently big numbers

Uwe Mueller um.computing at arcor.de
Sun Jun 28 19:55:06 CEST 2009


This bug report concerns GMP versions 4.2.1, 4.3.1 and probably also
others. It contains an attached test program, an error description and a
suggested patch.

The issue is shown by the attached test program. It uses two different
ways to find the string representation of some big numbers. One way
makes use of the function mpf_get_str, the other uses gmp_asprintf. In
systems where the size of the type mp_exp_t is larger than that of
int, the function gmp_asprintf will lead to wrong results for
sufficiently big numbers.

The test program does not take any arguments.

Error description:
------------------
For big numbers, the string returned from the function gmp_asprintf
has a wrong exponent. E.g. in my system, the test program prints the
following lines (among others):

...
2^1000000000000 =
mpf_get_str:  .957624423149274328480e+301029995664
gmp_asprintf: 9.57624423149274328481e+382284943
2^10000000000000 =
mpf_get_str:  .648562952955583895744e+3010299956640
gmp_asprintf: 6.48562952955583895744e-472117857
...

My system is running on a 64-bit AMD processor with OS x86_64
GNU/Linux and gcc version 4.1.2 20061115 (prerelease) (Debian
4.1.1-21). "long int" has 64 bits here, "int" has 32 bits here.

Error analysis
--------------
In my opinion, the reason is that gmp_asprintf formats the exponent as
int instead of long int.

Therefore, I would suggest the following patch:

diff -Naur gmp-4.3.1/printf/doprnt.c gmp-4.3.1_patch/printf/doprnt.c
--- gmp-4.3.1/printf/doprnt.c    2009-05-12 06:12:12.000000000 +0000
+++ gmp-4.3.1_patch/printf/doprnt.c    2009-06-13 23:22:15.000000000 +0000
@@ -211,7 +211,7 @@
 
       param.base = 10;
       param.conv = 0;
-      param.expfmt = "e%c%02d";
+      param.expfmt = "e%c%02ld";
       param.exptimes4 = 0;
       param.fill = ' ';
       param.justify = DOPRNT_JUSTIFY_RIGHT;
@@ -239,11 +239,11 @@
            and there's no leading zeros on the exponent (which is in
            fact bit-based) */
         param.base = 16;
-        param.expfmt = "p%c%d";
+        param.expfmt = "p%c%ld";
         goto conv_a;
       case 'A':
         param.base = -16;
-        param.expfmt = "P%c%d";
+        param.expfmt = "P%c%ld";
       conv_a:
         param.conv = DOPRNT_CONV_SCIENTIFIC;
         param.exptimes4 = 1;
@@ -350,7 +350,7 @@
 
       case 'E':
         param.base = -10;
-        param.expfmt = "E%c%02d";
+        param.expfmt = "E%c%02ld";
         /*FALLTHRU*/
       case 'e':
         param.conv = DOPRNT_CONV_SCIENTIFIC;
@@ -403,7 +403,7 @@
 
       case 'G':
         param.base = -10;
-        param.expfmt = "E%c%02d";
+        param.expfmt = "E%c%02ld";
         /*FALLTHRU*/
       case 'g':
         param.conv = DOPRNT_CONV_GENERAL;
diff -Naur gmp-4.3.1/printf/doprntf.c gmp-4.3.1_patch/printf/doprntf.c
--- gmp-4.3.1/printf/doprntf.c    2009-05-12 06:12:12.000000000 +0000
+++ gmp-4.3.1_patch/printf/doprntf.c    2009-06-14 02:48:16.000000000 +0000
@@ -231,8 +231,8 @@
 
   case DOPRNT_CONV_SCIENTIFIC:
     {
-      int   expval;
-      char  expsign;
+      long int  expval;
+      char      expsign;
 
       if (prec <= -1)
     prec = MAX (0, len-1);   /* retain all digits */



More information about the gmp-bugs mailing list