Gerhard Niklasch on Thu, 28 Dec 2000 21:09:31 +0100 (MET)


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

Re: Run-time errors


In response to:
> Message-ID: <Pine.SOL.3.96.1001228113644.3548A-100000@elios>
> Date: Thu, 28 Dec 2000 11:45:14 +0000 (GMT)
> From: Mark Chimley <M.Chimley@bristol.ac.uk>
> To: pari-users@list.cr.yp.to
> 
> I am running Debian Linux on a PC and compiling using gcc and version
> 2.0.1 of the pari library. I have the following code:

2.1.0 ?

> pari_init (500000, 1000);
> Gen n = 0;
> n = nextprime (n);

Here is a near-minimal complete program:

$ cat first.c
#include "pari.h"

int
main(int argc, char **argv) {
  GEN n;
  pari_init (500000, 1000);
  n = gzero;
  n = nextprime (n);
  printf("The oddest prime of all is ");
  output(n);
  exit(0);
}

Given the compiler I'm using and where I have the header and
libraries installed, I'm compiling it like this:

$ cc -I ~/pari/include/pari -o first first.c -L ~/pari/lib -R ~/pari/lib \
 -lpari -lm
$ ./first
The oddest prime of all is 2
$ 

> At run-time this gives "Incorrect type in gceil". I have also tried
> using isprime (n), which gave "Segmentation fault". I get the impression
> that something is fundamentally wrong here, since this is the first time
> I have tried to compile anything after installing the software.
> Alternatively, I might be missing something obvious. Any
> clues?

Explanation:  a GEN is a pointer at a PARI data structure.  If
you initialize n by writing
  GEN n = 0;
then n is a NULL pointer, which doesn't reference anything, and which
will cause a segmentation violation exception on most every platform
when you try to dereference it.  Both nextprime() and isprime() need
to dereference the pointer you're passing in, in order to find out
what kind of PARI object you're giving them to work on  (t_INT, t_REAL,
something else entirely,...).

To initialize n to the PARI integer zero, you can do as I did above
and let it point at one "Platonic" zero object which libpari gives
you for free, along with the symbol gzero naming its address.  The
nextprime() function, following the pointer n, will then pick up
this object and Do The Right Thing.

Alternatively, you could create your own 0-valued PARI integer on
the PARI stack and use that.  The first approach is marginally
more efficient since many PARI functions for which the number 0
has special significance first check whether they were passed the
gzero pointer, and only if not, proceed to check whether the pointer
they were passed points at a 0-valued integer object.

Indeed, the following way of using the C-long to PARI-t_INT converter
stoi():

{
  GEN n;
  pari_init (500000, 1000);
  n = stoi(0L);  /* stoi() does take a C long, rather than a pointer! */
  ...
}

will _not_ create a 0-valued integer on the stack:  stoi(0) itself
traps the special case and returns the special gzero pointer!

You can check this by using the %p format specifier of printf()
to display the pointers as hexadecimal addresses:
  printf("%p %p\n", (void *)gzero, (void *)(stoi(0)));
which on my box produces
ed480 ed480
(of course you can also read the source code of stoi() ...).

In either case, you probably want to keep track of garbage accumulating
on the PARI stack for all but the most trivial programs:

{
  GEN n;
  long av;
  pari_init ( 500000, 1000);
  av = avma; /* remember where we were */
  /* ... compute something ... */
  avma = av; /* reset the stack to its empty state */
}

(In practice, you'd rarely reset the stack like this -- most of the
time you'll want to preserve the final result of the computation
which will then need to be copied from the current head of the stack
to a position just below av;  the gerepile -- as in "gere pile",
"administrate the stack" -- family of functions is your friend.
The user manual discusses this topic in great detail, and, speaking
from experience, even after having read that chapter carefully several
times, you should be prepared to encounter interesting surprises...)

Hope this helps,
Gerhard