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