Question about creating and displaying mpf

Markus Törnqvist mjt at
Tue Sep 14 15:59:57 CEST 2010


I just found GMP and its Python bindings as a good replacement for the
dead-slow Python Decimal data type.

However, being new to extending Python, I have annoying memory leaks that
can't be found with Valgrind, as it doesn't understand Python's memory

Therefore I came up with the idea of using the C structures directly,
which might be a bit faster than going through the Python boilerplate,
but that didn't turn out painlessly either.

In Python I re-use the old Decimal interface, so I create gmpy.mpf
objects like D('1.678')

When I print it out in C code, from the Python object, its printed as

* Question one is: Why is that not the given value? Did it store
it badly, like a regular badly-rounded float, or is that representation only?

I'm not entirely clear on the innards of gmpy, but it seems it uses
its own PympfObject types for data storage.

The way I found to access the original data is the Pympf_AS_MPF macro, which
is (((PympfObject *)(foo))->f) and is used in gmpy code.

For me, however, it doesn't work.

  gmp_printf("%f\n", (((PympfObject *)(foo))->f)); // prints out 0.000000

foo is a regular PyObject *, but PympfObject stores the mpf_t in ->f so
that should, I guess, just work, but doesn't.

Using gdb (and the appropriate Python macros) I can get something meaningful
out like

  (gdb) print Pympf_ascii(foo, 10, 0, -2, 8, 0)
  $2 = (PyObject *) 0x10770f0
  (gdb) pyo $2
  object  : '1.66599999999999999999'
  type    : str
  refcount: 1
  address : 0x10770f0

but that only works on Python objects. But it kinda goes to prove that
the value is somehow accessible :)

* So question number two is: what am I missing here? Why can't I use
the Pympf_AS_MPF macro to gmp_printf() the real value?

I try to set it into new variables, like

  mpf_t tmp;

  mpf_set(tmp, Pympf_AS_MPF(foo));

And gmp_printf(...) tells me 0.000000

No matter how I try to set this, it fails

  mpf_t tmp;

  mpf_set_str(tmp, PyString_AsString(PyObject_Str(foo)), 10);

Same thing(!)


  mpf_t tmp;

  mpf_set_ui(tmp, 42);

Does not work; it's all about zeroes.

This is so strange, those are vastly different things, every one, but
all fail the same way.

What *does* semi-work is getting the string the hard way
from the MPF:

  char *mpf_in_buffer;
  char *mpf_out_buffer;
  mp_exp_t the_exp;

  int base = 10;
  int digits = 0;

  int tmp_retval = 0;

  mpf_in_buffer = mpf_get_str(0, &the_exp, base, digits, Pympf_AS_MPF(foo));
  printf("\tmpf_in_buffer: %s\n", mpf_in_buffer);

  sprintf(mpf_out_buffer, "%s@%d", mpf_in_buffer, (int) the_exp);
  printf("\tmpf_out_buffer: %s\n", mpf_out_buffer);

  tmp_retval = mpf_set_str(tmp, mpf_out_buffer, base);
  gmp_printf("\ttmp (%d) %f\n", tmp_retval, tmp);

Results in the output

  mpf_in_buffer: 167800000000000000002
  mpf_out_buffer: 167800000000000000002 at 1
  tmp (0) 0.000000

I do assume that @ is the correct separator between mantissa and exponent,
as the documentation says "if the base is 10 or less" and tmp_retval == 0.

Clearly the Pympf_AS_MPF macro can't be all bad because it magickally
works for mpf_get_str(). But why?

* What am I doing wrong?

There is the saying "select() is not broken", but I've been
studying the GMP manual harder than anything and now
just breaking apart here; it would be nice of the bug was
actually in Debian's libgmp3-dev (2:4.3.2+dfsg-1)

Are there any convenient GDB macros for GMP?
I tried writing my own to print all relevant data for
an MPF:

define mpf
  set $ob = $arg0
  printf "size: %d\n", $ob->_mp_size
  printf "prec: %d\n", $ob->_mp_prec
  printf "limbs:\n"
  set $i = 0
  while (++$i <= $ob->_mp_size)
    printf "\t%d\n", $ob->_mp_d[$i]

but realised how hard it actually is to represent
the limbs, the hard way with mpf_get_str, and as I clearly
can't call gmp_printf() or anything else usefully,
I guess I'm screwed, right?

Thanks for any help!


More information about the gmp-discuss mailing list