pika-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Pika-dev] cvt-bignum and cvt-bigrat


From: Matthew Dempsky
Subject: [Pika-dev] cvt-bignum and cvt-bigrat
Date: Tue, 13 Jan 2004 21:34:15 +0100
User-agent: Gnus/5.1002 (Gnus v5.10.2) Emacs/21.3 (gnu/linux)

Tom asked me about this in IRC, so here goes:

18:26 < tomlord> i haven't looked at the code yet but i have a
                 question about converting numbers to bignums.
18:27 < tomlord> i mean converting scheme nums to gmp.
18:27 < tomlord> so --- are you careful, in the code you've written,
                 to be sure that if you take a gmp that is shared by a
                 scheme value, that that scheme value is protected
                 while you use it.
18:27 < tomlord> ?
18:27 < tomlord> and:
18:28 < tomlord> what's the right thing for an ffi, there.

Okay, my short answer was that I think the external interface is safe,
but I'll give a longer explanation as to why here.

The two gmp types in use by Pika right now are mpz_t (bignum) and
mpq_t (bigrat).  I'm only going to describe the mpz_t functions, but
for the most part it's equally applicable for mpq_t functions.

First, mpz_t is basically defined:

    typedef struct __mpz_struct mpz_t[1];

The __mpz_struct contains three variables -- a pointer to the limbs
containing the number itself, and two integers counting the number of
allocated words and the number of words in use.

gmp also defines a constructor, mpz_init, and a destructor, mpz_clear,
that need to be called on the defined variables as appropriate.

Now, the reason for the above typedef is so that in user code we can
define a mpz_t variable and then the variable name is actually a
pointer that can be conveniently passed to the mpz_* functions like
so:

    mpz_t a, b, c;

    [...]

    mpz_add (a, b, c);

This performs the operation "a = b + c".  It's my understanding that
this routine basically ensures that a has enough memory allocated to
store the result of b + c and if not allocates more.  Then it computes
the result and stores it in a's dynamic memory.

Now, the concern you had was over concerns of what memory the user has
and the answer is basically "whatever gmp thinks is safe for us to
use."  Here's the implementation for scm_reps_number_to_bignum (this
is code from a patch after you merged incase you're wondering where it
is)

    t_scm_error
    scm_reps_number_to_bignum (mpz_ptr result,
                               t_scm_arena arena,
                               t_scm_word * value)
    {
      switch (scm_get_numeric_type (arena, value))
        {
    
    [...]
    
        case scm_num_bignum:
          {
            mpz_set (result, scm_bignum_value (arena, value));
            return 0;
          }
    
    [...]
    
        }
    }

scm_bignum_value just returns a mpz_srcptr for the internally held
bignum value.  I don't know if gmp uses reference counting for numbers
or if it just reuses the memory already initialized in result (if
any), but either way Pika's code is at least consistant in it's
behaviour with what a gmp user expects (i.e. they must use mpz_init
before calling scm_number_to_bignum and mpz_clear once they're done
with their variable - I should probably add a comment regarding this
to the documentation) and they can't modify the value held internally
by the bignum.

The refactoring that I said caused aliasing issues is that I changed
scm_make_bignum to return a mpz_ptr so that it would be simpler to
implement scm_reps_add efficiently like this:

    mpz_add (scm_make_bignum (result, arena),
             scm_bignum_value (arena, a),
             scm_bignum_value (arena, b));

This eliminates the temporary mpz_t I had to generate earlier, but you
should be able to see the aliasing issue.  Of course this is just an
implementation issue -- this issue isn't visible from outside the FFI
(unless you think the numeric types should be publicly available).

Um, I think that's all there is to know about the gmp stuff, but if I
managed to miss something I'll elaborate on that more (this email's
already getting far too long).

-jivera




reply via email to

[Prev in Thread] Current Thread [Next in Thread]