Printing out mpf_class inside gdb

Stephen torri storri at torri.org
Fri Jul 16 06:22:44 CEST 2004


I wish the archives were searchable. So I am going risk repeating
something. I want to print out a mpf_class type inside gdb. I am having
difficulty in a large program figuring out why a mpf_class value goes
undefined. I will describe in this example.

I have a class which writes mpf_class types to a file. It writes two to
a file in sequential order. In turn these are read from the file in
sequential order. So if val1 = 509485095850.04 and val2 = 394805995.39
then the values writen out and read back should match.

That is not the case is. Here is a test example:

bash-2.05b$ ./test
Write
  time: 509485095850.04
  time2: 394805995.39
Read
  time: 5.09485e+113
  time2: 94806000

You will notice that the times don't match. So what did I do? Here is
the code:

#include <fstream>
#include <iostream>
#include <inttypes.h>
#include <gmpxx.h>
#include <string>

std::ofstream out_file;
std::ifstream in_file;

int main (int, char*)
{

  out_file.open("mpz_test");

  if (! out_file.is_open())
    {
      std::cerr << "Cannot open mpz_test for writing" << std::endl;
    }

  mpf_class m_time_stamp  (509485095850.04,15);
  mpf_class m_time_stamp2 (394805995.39,15);

  std::cout << "Write" << std::endl;
  std::cout.precision(15);
  std::cout << "  time: " << m_time_stamp << std::endl;
  std::cout << "  time2: " << m_time_stamp2 << std::endl;

  out_file << m_time_stamp;
  out_file << m_time_stamp2;
  out_file.close();

  in_file.open("mpz_test");

  if (! in_file.is_open())
    {
      std::cerr << "Cannot open mpz_test for reading" << std::endl;
    }

  mpf_class r_time_stamp;
  mpf_class r_time_stamp2;

  in_file >> r_time_stamp;
  in_file >> r_time_stamp2;

  std::cout << "Read" << std::endl;
  std::cout.precision(15);
  std::cout << "  time: " << r_time_stamp << std::endl;
  std::cout << "  time2: " << r_time_stamp2 << std::endl;

  return 0;
}


All I did to write the values was to use the operator<< function.
Reading was done likewise with the operator>> function.

So what does the binary file look like?

bash-2.05b$ od -bc mpz_test
0000000 065 056 060 071 064 070 065 145 053 061 061 063 056 071 064 070
          5   .   0   9   4   8   5   e   +   1   1   3   .   9   4   8
0000020 060 066 145 053 060 070
          0   6   e   +   0   8

So the problem is a bit clearer here. The human knows that the first
value eds at the hex sequence 061 061 (11 in base 10). Well the program
stops parsing the first number by the value 056 (period character '.').
So the second number ofcourse is wrong because its reading two bytes to
the right from where it should. 

So where is the problem if the example appears to be right? Its in
cxx/ismpf.cc at line 110. The operator>> function at this point has the
input stream with the reader head like one a tape over the '1' digit. So
it reads in the exponent. It says the exponent is 113 when we know the
first number has a exponent of 11. So when we read the next value  we
get . 9 4 8 0 6 e + 0 8. Which the program will move the period one
digit to the right and reduce the exponent by 1. Therefore since our
precision was set to 15 we see the output value of 94806000.

What is the fix? Simply add a delimeter to the end, \0 , to every
mpf_class type when written to a file.

osmpf.cc fix: Add a '\0' character to the end of a mpf_class type.
=======================================================================
--- osmpf.cc    2001-10-10 17:13:35.000000000 -0400
+++ /home/storri/src/gmp-fixed-4.1.3/cxx/osmpf.cc       2004-06-11
16:26:07.000000000 -0400
@@ -50,4 +50,5 @@

   gmp_allocated_string alloc = result;
-  return o.write (result, strlen (result));
+  o.write (result, strlen (result));
+  return o.put('\0'); //put delimiter



ismpf.cc: Read up to end-of-file or '\0' character.
=======================================================================
bash-2.05b$ diff -U2 ismpf.cc ~/src/gmp-fixed-4.1.3/cxx/ismpf.cc
--- ismpf.cc    2002-11-12 02:25:59.000000000 -0500
+++ /home/storri/src/gmp-fixed-4.1.3/cxx/ismpf.cc       2004-06-11
16:24:46.000000000 -0400
@@ -58,9 +58,9 @@
     {
       if (c == '-')
-       s = "-";
+        s = "-";
       i.get(c);

       while (isspace(c) && i.get(c)) // skip whitespace
-       ;
+        ;
     }

@@ -100,11 +100,11 @@

       if (c == '-' || c == '+') // sign
-       {
-         s += c;
-         i.get(c);
-
-         while (isspace(c) && i.get(c)) // skip whitespace
-           ;
-       }
+        {
+          s += c;
+          i.get(c);
+
+          while (isspace(c) && i.get(c)) // skip whitespace
+            ;
+        }

       __gmp_istream_set_digits(s, i, c, ok, base); // read the exponent
@@ -112,5 +112,12 @@

   if (i.good()) // last character read was non-numeric
-    i.putback(c);
+    {
+      if (c != '\0') //did not read delimiter!
+        {
+          i.putback(c);
+          goto fail;
+        }
+      //else read delimiter
+    }
   else if (i.eof() && ok) // stopped just before eof
     i.clear();


The top two code segments can be ignored since code has not been changed
other than its formatting in the file. The last one is the fix. When we
find a non-numeric character we stop reading the number. Since we added
the '\0' character to the end of a mpf_class number we get the original
number we put in.

My fix is shown in this test example below. The only change I made
beyond my fix was to set the output precision of out_file so that I got
my whole number into the file.

bash-2.05b$ ./test2
Write
  time: 509485095850.04
  time2: 394805995.39
Read
  time: 509485095850.04
  time2: 394805995.39

bash-2.05b$ od -bc mpz_test
0000000 065 056 060 071 064 070 065 145 053 061 061 000 063 056 071 064
          5   .   0   9   4   8   5   e   +   1   1  \0   3   .   9   4
0000020 070 060 066 145 053 060 070
          8   0   6   e   +   0   8


=====================================================
#include <fstream>
#include <iostream>
#include <inttypes.h>
#include <gmpxx.h>
#include <string>

std::ofstream out_file;
std::ifstream in_file;

int main (int, char*)
{

  out_file.open("mpz_test");

  if (! out_file.is_open())
    {
      std::cerr << "Cannot open mpz_test for writing" << std::endl;
    }

  mpf_class m_time_stamp  (509485095850.04,15);
  mpf_class m_time_stamp2 (394805995.39,15);

  std::cout << "Write" << std::endl;
  std::cout.precision(15);
  std::cout << "  time: " << m_time_stamp << std::endl;
  std::cout << "  time2: " << m_time_stamp2 << std::endl;

  out_file.precision(15);
  out_file << m_time_stamp << '\0';
  out_file << m_time_stamp2;
  out_file.close();

  in_file.open("mpz_test");

  if (! in_file.is_open())
    {
      std::cerr << "Cannot open mpz_test for reading" << std::endl;
    }

  mpf_class r_time_stamp;
  mpf_class r_time_stamp2;

  in_file >> r_time_stamp;
  char c;
  in_file >> c;
  if ( c != '\0' )
    {
      std::cout << "Read invalid delimiter: ";
      std::cout << c << std::endl;
      exit(-1);
    }
  in_file >> r_time_stamp2;

  std::cout << "Read" << std::endl;
  std::cout.precision(15);
  std::cout << "  time: " << r_time_stamp << std::endl;
  std::cout << "  time2: " << r_time_stamp2 << std::endl;

  return 0;
}

Stephen



More information about the gmp-bugs mailing list