summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1994-12-12 17:49:55 +0000
committerJim Meyering <jim@meyering.net>1994-12-12 17:49:55 +0000
commit0050411112482f5aac27a314ef0ee926003afeac (patch)
tree50fc1dbcbdd0a688e10c205bf9cebb0c007e02cc /src
parent5bfdd91cdf170bec9fb0a9eed7a259242925c1c4 (diff)
downloadcoreutils-0050411112482f5aac27a314ef0ee926003afeac.tar.xz
.
Diffstat (limited to 'src')
-rw-r--r--src/factor.c86
-rw-r--r--src/spline.c735
2 files changed, 821 insertions, 0 deletions
diff --git a/src/factor.c b/src/factor.c
new file mode 100644
index 000000000..967799e1c
--- /dev/null
+++ b/src/factor.c
@@ -0,0 +1,86 @@
+/* factor -- print factors of n. lose if n > 2^32.
+ Copyright (C) 1986 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Paul Rubin <phr@ocf.berkeley.edu>. */
+
+#include <stdio.h>
+
+void do_stdin ();
+void factor ();
+
+void
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ if (argc == 1)
+ do_stdin ();
+ else if (argc == 2)
+ factor ((unsigned) atoi (argv[1]));
+ else
+ {
+ fprintf (stderr, "Usage: %s [number]\n", argv[0]);
+ exit (1);
+ }
+ exit (0);
+}
+
+void
+factor (n0)
+ unsigned long n0;
+{
+ register unsigned long n = n0, d;
+
+ if (n < 1)
+ return;
+
+ while (n % 2 == 0)
+ {
+ printf ("\t2\n");
+ n /= 2;
+ }
+ /* The exit condition in the following loop is correct because
+ any time it is tested one of these 3 conditions holds:
+ (1) d divides n
+ (2) n is prime
+ (3) n is composite but has no factors less than d.
+ If (1) or (2) obviously the right thing happens.
+ If (3), then since n is composite it is >= d^2. */
+ for (d = 3; d * d <= n; d += 2)
+ {
+ while (n % d == 0)
+ {
+ printf ("\t%d\n", d);
+ n /= d;
+ }
+ }
+ if (n != 1 || n0 == 1)
+ printf ("\t%d\n", n);
+}
+
+void
+do_stdin ()
+{
+ char buf[1000];
+
+ for (;;)
+ {
+ if (fgets (buf, sizeof buf, stdin) == 0)
+ exit (0);
+ factor ((unsigned long) atoi (buf));
+ }
+}
diff --git a/src/spline.c b/src/spline.c
new file mode 100644
index 000000000..fb6a8627a
--- /dev/null
+++ b/src/spline.c
@@ -0,0 +1,735 @@
+/* spline.c -- Do spline interpolation. */
+
+/******************************************************************************
+ David L. Fox
+ 2140 Braun Dr.
+ Golden, CO 80401
+
+This program has been placed in the public domain by its author.
+
+Version Date Change
+1.1 17 Dec 1985 Modify getdata() to realloc() more memory if needed.
+1.0 14 May 1985
+
+spline [options] [file]
+
+Spline reads pairs of numbers from file (or the standard input, if file is missing).
+The pairs are interpreted as abscissas and ordinates of a function. The output of
+spline consists of similar pairs generated from the input by interpolation with
+cubic splines. (See R. W. Hamming, Numerical Methods for Scientists and Engineers,
+2nd ed., pp. 349ff.) There are sufficiently many points in the output to appear
+smooth when plotted (e.g., by graph(1)). The output points are approximately evenly
+spaced and include the input points.
+
+There may be one or more options of the form: -o [argument [arg2] ].
+
+The available options are:
+
+-a Generate abscissa values automatically. The input consists of a list of
+ ordinates. The generated abscissas are evenly spaced with spacing given by
+ the argument, or 1 if the next argument is not a number.
+
+-f Set the first derivative of the spline function at the left and right end
+ points to the first and second arguments following -f. If only one numerical
+ argument follows -f then that value is used for both left and right end points.
+
+-k The argument of the k option is the value of the constant used to calculate
+ the boundary values by y''[0] = ky''[1] and y''[n] = ky''[n-1]. The default
+ value is k = 0.
+
+-m The argument gives the maximum number of input data points. The default is 1000.
+ If the input contains more than this many points additional memory will be
+ allocated. This option may be used to slightly increase efficiency for large
+ data sets or reduce the amount of memory required for small data sets.
+
+-n The number of output points is given by the argument. The default value is 100.
+
+-p The splines used for interpolation are forced to be periodic, i.e. y'[0] = y'[n].
+ The first and last ordinates should be equal.
+
+-s Set the second derivative of the spline function at the left and right end
+ points to the first and second arguments following -s. If only one numerical
+ argument follows -s then that value is used for both left and right end points.
+
+-x The argument (and arg2, if present) are the lower (and upper) limits on the
+ abscissa values in the output. If the x option is not specified these limits
+ are calculated from the data. Automatic abscissas start at the lower limit
+ (default 0).
+
+The data need not be monotonic in x but all the x values must be distinct.
+Non-numeric data in the input is ignored.
+******************************************************************************/
+
+#include <a:stdio.h>
+#include <ctype.h>
+
+/* The constant DOUBLE is a compile time switch.
+ If #define DOUBLE appears here double pecision variables are
+ used to store all data and parameters.
+ Otherwise, float variables are used for the data.
+ For most smoothing and and interpolation applications single
+ precision is more than adequate.
+ Double precision is used to solve the system of linear equations
+ in either case.
+*/
+/* #define DOUBLE */
+
+#ifdef DOUBLE
+#define double real; /* Type used for data storage. */
+#define IFMT "%F" /* Input format. */
+#define OFMT "%18.14g %18.14g\n" /* Output format. */
+#else
+#define float real; /* Type used for data storage. */
+#define IFMT "%f" /* Input format. */
+#define OFMT "%8.5g %8.5g\n" /* Output format. */
+#endif
+
+/* Numerical constants: These may be machine and/or precision dependent. */
+#define HUGE (1.e38) /* Largest floating point number. */
+#define EPS 1.e-5 /* Test for zero when solving linear equations. */
+
+/* Default parameters */
+#define NPTS 1000
+#define NINT 100
+#define DEFSTEP 1. /* Default step size for automatic abcissas. */
+#define DEFBVK 0. /* Default boundary value constant. */
+
+/* Boundary condition types. */
+#define EXTRAP 0 /* Extrapolate second derivative:
+ y''(0) = k * y''(1), y''(n) = k * y''(n-1) */
+#define FDERIV 1 /* Fixed first derivatives y'(0) and y'(n). */
+#define SDERIV 2 /* Fixed second derivatives y''(0) and y''(n). */
+#define PERIOD 3 /* Periodic: derivatives equal at end points. */
+
+/* Token types for command line processing. */
+#define OPTION 1
+#define NUMBER 2
+#define OTHER 3
+
+/* Define error numbers. */
+#define MEMERR 1
+#define NODATA 2
+#define BADOPT 4
+#define BADFILE 5
+#define XTRAARG 6
+#define XTRAPTS 7
+#define SINGERR 8
+#define DUPX 9
+#define BADBC 10
+#define RANGERR 11
+
+/* Constants and flags are global. */
+int aflag = FALSE; /* Automatic abscissa flag. */
+real step = DEFSTEP; /* Spacing for automatic abscissas. */
+int bdcode = EXTRAP; /* Type of boundary conditions:
+ 0 extrapolate f'' with coeficient k.
+ 1 first derivatives given
+ 2 second derivatives given
+ 3 periodic */
+real leftd = 0., /* Boundary values of derivatives. */
+ rightd = 0.;
+real k = DEFBVK; /* Boundary value constant. */
+int rflag = 0; /* 0: take range from data, 1: min. given, 2: min. & max. given. */
+real xmin = HUGE, xmax; /* Output range. */
+unsigned nint = NINT; /* Number of intervals in output. */
+unsigned maxpts = NPTS; /* Maximun number of points. */
+unsigned nknots = 0; /* Number of input points. */
+int sflag = FALSE; /* If TRUE data must be sorted. */
+char *datafile; /* Name of data file */
+
+int xcompare(); /* Function to compare x values of two data points. */
+
+struct pair {
+ real x, y;
+ } *data; /* Points to list of data points. */
+
+struct bandm {
+ double diag, upper, rhs;
+ } *eqns; /* Points to elements of band matrix used to calculate
+ coefficients of the splines. */
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ setup(argc, argv);
+ if (nknots == 1) { /* Cannot interpolate with one data point. */
+ printf(OFMT,data->x, data->y);
+ exit(0);
+ }
+ if (sflag) /* Sort data if needed. */
+ qsort(data, nknots, sizeof(struct pair), xcompare);
+ calcspline();
+ interpolate();
+}
+
+/* xcompare -- Compare abcissas of two data points (for qsort). */
+xcompare(arg1, arg2)
+struct pair *arg1, *arg2;
+{
+ if (arg1->x > arg2->x)
+ return(1);
+ else if (arg1->x < arg2->x)
+ return(-1);
+ else
+ return(0);
+}
+
+/* error -- Print error message and abort fatal errors. */
+error(errno, auxmsg)
+int errno;
+char *auxmsg;
+{ char *msg;
+ int fatal, usemsg;
+ static char *usage =
+ "usage: spline [options] [file]\noptions:\n",
+ *options = "-a spacing\n-k const\n-n intervals\n-m points\n-p\n-x xmin xmax\n";
+
+ fatal = TRUE; /* Default is fatal error. */
+ usemsg = FALSE; /* Default no usage message. */
+ fprintf(stderr, "spline: ");
+ switch(errno) {
+ case MEMERR:
+ msg = "not enough memory for %u data points\n";
+ break;
+ case NODATA:
+ msg = "data file %s empty\n";
+ break;
+ case BADOPT:
+ msg = "unknown option: %c\n";
+ usemsg = TRUE;
+ break;
+ case BADFILE:
+ msg = "cannot open file: %s\n";
+ break;
+ case XTRAARG:
+ msg = "extra argument ignored: %s\n";
+ fatal = FALSE;
+ usemsg = TRUE;
+ break;
+ case XTRAPTS:
+ fatal = FALSE;
+ msg = "%s";
+ break;
+ case DUPX:
+ msg = "duplicate abcissa value: %s\n";
+ break;
+ case RANGERR:
+ msg = "xmax < xmin not allowed %s\n";
+ break;
+ /* The following errors "can't happen." */
+ /* If they occur some sort of bug is indicated. */
+ case SINGERR:
+ msg = "singular matrix encountered %s\n";
+ break;
+ case BADBC:
+ msg = "internal error: bad boundary value code %d\n";
+ break;
+ default:
+ fprintf(stderr, "unknown error number: %d\n", errno);
+ exit(1);
+ }
+ fprintf(stderr, msg, auxmsg);
+ if (usemsg)
+ fprintf(stderr,"%s%s", usage, options);
+ if (fatal)
+ exit(1);
+}
+
+/* setup -- Initalize all constants and read data. */
+setup(argc, argv)
+int argc;
+char **argv;
+{ char *malloc();
+ FILE fdinp, /* Source of input. */
+ doarg();
+
+ fdinp = doarg(argc, argv); /* Process command line arguments. */
+
+ /* Allocate memory for data and band matrix of coefficients. */
+ if ((data = malloc(maxpts*sizeof(struct pair))) == NULL) {
+ error(MEMERR, (char *)maxpts);
+ }
+
+ getdata(fdinp); /* Read data from fdinp. */
+ if (fdinp != stdin)
+ fclose(fdinp); /* Close input data file. */
+ if (nknots == 0) {
+ error(NODATA, datafile);
+ }
+ /* Allocate memory for calculation of spline coefficients. */
+ if ((eqns = malloc((nknots+1)*sizeof(struct bandm))) == NULL) {
+ error(MEMERR, (char *)nknots);
+ }
+}
+
+/* doarg -- Process arguments. */
+FILE
+doarg(argc, argv)
+int argc;
+char **argv;
+{ int i, type;
+ double atof();
+ char *s, str[15];
+ FILE fdinp;
+
+ s = argv[i=1];
+ type = gettok(&i, &s, argv, str);
+ do {
+ if (type == OPTION) {
+ switch(*str) {
+ case 'a': /* Automatic abscissa. */
+ aflag = TRUE;
+ rflag = rflag < 2 ? 1 : rflag;
+ if (xmin == HUGE) /* Initialize xmin, if needed. */
+ xmin = 0.;
+ if ((type = gettok(&i, &s, argv, str)) == NUMBER) {
+ if ((step = atof(str)) <= 0.)
+ error(RANGERR,"");
+ type = gettok(&i, &s, argv, str);
+ }
+ break;
+ case 'f': /* Fix first derivative at boundaries. */
+ bdcode = FDERIV;
+ if ((type = gettok(&i, &s, argv, str)) == NUMBER) {
+ leftd = atof(str);
+ if ((type = gettok(&i, &s, argv, str)) == NUMBER) {
+ rightd = atof(str);
+ type = gettok(&i, &s, argv, str);
+ }
+ else {
+ rightd = leftd;
+ }
+ }
+ break;
+ case 'k': /* Set boundary value constant. */
+ bdcode = EXTRAP;
+ if ((type = gettok(&i, &s, argv, str)) == NUMBER) {
+ k = atof(str);
+ type = gettok(&i, &s, argv, str);
+ }
+ break;
+ case 'm': /* Set number of intervals in output. */
+ if ((type = gettok(&i, &s, argv, str)) == NUMBER) {
+ maxpts = (unsigned)atoi(str);
+ type = gettok(&i, &s, argv, str);
+ }
+ break;
+ case 'n': /* Set number of intervals in output. */
+ if ((type = gettok(&i, &s, argv, str)) == NUMBER) {
+ nint = (unsigned)atoi(str);
+ type = gettok(&i, &s, argv, str);
+ }
+ break;
+ case 'p': /* Require periodic interpolation function. */
+ bdcode = PERIOD;
+ type = gettok(&i, &s, argv, str);
+ break;
+ case 's': /* Fix second derivative at boundaries. */
+ bdcode = SDERIV;
+ if ((type = gettok(&i, &s, argv, str)) == NUMBER) {
+ leftd = atof(str);
+ if ((type = gettok(&i, &s, argv, str)) == NUMBER) {
+ rightd = atof(str);
+ type = gettok(&i, &s, argv, str);
+ }
+ else {
+ rightd = leftd;
+ }
+ }
+ break;
+ case 'x': /* Set range of x values. */
+ rflag = 1;
+ if ((type = gettok(&i, &s, argv, str)) == NUMBER) {
+ xmin = atof(str);
+ if ((type = gettok(&i, &s, argv, str)) == NUMBER) {
+ xmax = atof(str);
+ rflag = 2;
+ type = gettok(&i, &s, argv, str);
+ if (xmax <= xmin)
+ error(RANGERR, "");
+ }
+ }
+ break;
+ default:
+ error(BADOPT, (char *)argv[i][1]);
+ }
+ }
+ else {
+ if (argc > i) {
+ datafile = argv[i];
+ if ((fdinp = fopen(argv[i++], "r")) == NULL) {
+ error(BADFILE, argv[i-1]);
+ }
+ if (argc > i)
+ error(XTRAARG, argv[i]);
+ }
+ else
+ fdinp = stdin;
+ break;
+ }
+ } while (i < argc);
+ return fdinp;
+}
+
+/* gettok -- Get one token from command line, return type. */
+gettok(indexp, locp, argv, str)
+int *indexp; /* Pointer to index in argv array. */
+char **locp; /* Pointer to current location in argv[*indexp]. */
+char **argv;
+char *str;
+{ char *s;
+ char *strcpy(), *strchr();
+ int type;
+
+ s = *locp;
+ while (isspace(*s) || *s == ',')
+ ++s;
+ if (*s == '\0') /* Look at next element in argv. */
+ s = argv[++*indexp];
+ if (*s == '-' && isalpha(s[1])) {
+ /* Found an option. */
+ *str = *++s;
+ str[1] = '\0';
+ ++s;
+ type = OPTION;
+ }
+ else if (isnumber(s)) {
+ while (isnumber(s))
+ *str++ = *s++;
+ *str = '\0';
+ type = NUMBER;
+ }
+ else {
+ strcpy(str, s);
+ s = strchr(s, '\0');
+ type = OTHER;
+ }
+ *locp = s;
+ return(type);
+}
+
+/* isnumber -- Return TRUE if argument is the ASCII representation of a number. */
+isnumber(string)
+char *string;
+{
+ if (isdigit(*string) ||
+ *string == '.' ||
+ *string == '+' ||
+ (*string == '-' && (isdigit(string[1]) || string[1] == '.')))
+ return(TRUE);
+ else
+ return(FALSE);
+}
+
+/* getdata -- Read data points from fdinp. */
+getdata(fdinp)
+FILE fdinp;
+{ int n, i;
+ real lastx, min, max;
+ struct pair *dp;
+ char msg[60], *realloc();
+
+ nknots = 0;
+ lastx = -HUGE;
+ dp = data; /* Point to head of list of data. */
+ min = HUGE;
+ max = -HUGE;
+ do {
+ if (aflag) { /* Generate abcissa. */
+ dp->x = xmin + nknots*step;
+ n = 0;
+ }
+ else { /* Read abcissa. */
+ while ((n = (fscanf(fdinp,IFMT,&dp->x))) == 0)
+ ; /* Skip non-numeric input. */
+ }
+ if (n == 1) {
+ if (min > dp->x)
+ min = dp->x;
+ if (max < dp->x)
+ max = dp->x;
+ if (lastx > dp->x) { /* Check for monotonicity. */
+ sflag = TRUE; /* Data must be sorted. */
+ }
+ lastx = dp->x;
+ }
+ /* Read ordinate. */
+ while ((n = (fscanf(fdinp, IFMT, &dp->y))) == 0)
+ ; /* Skip non-numeric input. */
+ if (++nknots >= maxpts) { /* Too many points, allocate more memory. */
+ if ((data = realloc(data, (maxpts *= 2)*sizeof(struct pair))) == NULL) {
+ error(MEMERR, (char *)maxpts);
+ }
+ dp = data + nknots;
+ sprintf(msg, "more than %d input points, more memory allocated\n",
+ maxpts/2);
+ error(XTRAPTS,msg);
+ }
+ else
+ ++dp;
+ } while (n == 1);
+ --nknots;
+ if (aflag) { /* Compute maximum ordinate. */
+ max = xmin + (nknots-1)*step;
+ }
+ if (rflag < 2) {
+ xmax = max;
+ if (rflag < 1)
+ xmin = min;
+ }
+}
+
+/* calcspline -- Calculate coeficients of spline functions. */
+calcspline()
+{
+ calccoef();
+ solvband();
+}
+
+/* calccoef -- Calculate coefficients of linear equations determining spline functions. */
+calccoef()
+{ int i, j;
+ struct bandm *ptr, tmp1, tmp2;
+ double h, h1;
+ char str[10];
+
+ ptr = eqns;
+ /* Initialize first row of matrix. */
+ if ((h1 = data[1].x - data[0].x) == 0.) {
+ sprintf(str, "%8.5g", data[0].x);
+ error(DUPX, str);
+ }
+ switch(bdcode) { /* First equation depends on boundary conditions. */
+ case EXTRAP:
+ ptr->upper = -k;
+ ptr->diag = 1.;
+ ptr->rhs = 0.;
+ break;
+ case FDERIV: /* Fixed first derivatives at ends. */
+ ptr->upper = 1.;
+ ptr->diag = 2.;
+ h = data[1].x - data[0].x;
+ ptr->rhs = 6.*((data[1].y - data[0].y)/(h*h) - leftd/h);
+ break;
+ case SDERIV:
+ ptr->upper = 0.;
+ ptr->diag = 1.;
+ ptr->rhs = leftd;
+ break;
+ case PERIOD: /* Periodic splines. */
+ ptr->upper = 1.;
+ ptr->diag = 2.;
+ break;
+ default:
+ error(BADBC, (char *) bdcode);
+ }
+ ++ptr;
+
+ /* Initialize rows 1 to n-1, sub-diagonal band is assumed to be 1. */
+ for (i=1; i < nknots-1; ++i, ++ptr) {
+ h = h1;
+ if ((h1 = data[i+1].x - data[i].x) == 0.) {
+ sprintf(str, "%8.5g", data[i].x);
+ error(DUPX, str);
+ }
+ ptr->diag = 2.*(h + h1)/h;
+ ptr->upper = h1/h;
+ ptr->rhs = 6.*((data[i+1].y-data[i].y)/(h*h1) -
+ (data[i].y - data[i-1].y)/(h*h));
+ }
+ /* Initialize last row. */
+ switch(bdcode) {
+ case EXTRAP: /* Standard case. */
+ ptr->diag = 1.;
+ ptr->upper = -k; /* Upper holds actual sub-diagonal value. */
+ ptr->rhs = 0.;
+ break;
+ case FDERIV: /* Fixed first derivatives at ends. */
+ ptr->upper = 1.;
+ ptr->diag = 2.;
+ h = data[nknots-1].x - data[nknots-2].x;
+ ptr->rhs = 6.*((data[nknots-2].y - data[nknots-1].y)/(h*h) + rightd/h);
+ break;
+ case SDERIV:
+ ptr->upper = 0.;
+ ptr->diag = 1.;
+ ptr->rhs = rightd;
+ break;
+ case PERIOD: /* Use periodic boundary conditions. */
+ /* First and last row are not in tridiagonal form. */
+ h = data[1].x - data[0].x;
+ h1 = data[nknots-1].x - data[nknots-2].x;
+ ptr->diag = 1.;
+ ptr->upper = 0.;
+ tmp1.diag = -1.;
+ tmp1.upper = 0;
+ tmp1.rhs = 0.;
+ tmp2.diag = 2.*h1/h;
+ tmp2.upper = h1/h;
+ tmp2.rhs = 6.*((data[1].y - data[0].y)/(h*h) -
+ (data[nknots-1].y - data[nknots-2].y)/(h1*h));
+ /* Transform periodic boundary equations to tri-diagonal form. */
+ for (i = 1; i < nknots - 1; ++i) {
+ tmp1.upper /= tmp1.diag;
+ tmp1.rhs /= tmp1.diag;
+ ptr->diag /= tmp1.diag;
+ ptr->upper /= tmp1.diag;
+ tmp1.diag = tmp1.upper - eqns[i].diag;
+ tmp1.upper = -eqns[i].upper;
+ tmp1.rhs -= eqns[i].rhs;
+ tmp2.upper /= tmp2.diag;
+ tmp2.rhs /= tmp2.diag;
+ eqns->diag /= tmp2.diag;
+ eqns->upper /= tmp2.diag;
+ tmp2.diag = tmp2.upper - eqns[nknots-1-i].diag/eqns[nknots-1-i].upper;
+ tmp2.upper = -1./eqns[nknots-1-i].upper;
+ tmp2.rhs -= eqns[nknots-1-i].rhs/eqns[nknots-1-i].upper;
+ }
+ /* Add in remaining terms of boundary condition equation. */
+ ptr->upper += tmp1.diag;
+ ptr->diag += tmp1.upper;
+ ptr->rhs = tmp1.rhs;
+ eqns->diag += tmp2.upper;
+ eqns->upper += tmp2.diag;
+ eqns->rhs = tmp2.rhs;
+ break;
+ default:
+ error(BADBC, (char *) bdcode);
+ }
+}
+
+/* solvband -- Solve band matrix for spline functions. */
+solvband()
+{ int i, flag;
+ struct bandm *ptr;
+ double k1;
+ double fabs();
+ int fcompare();
+
+ ptr = eqns;
+ flag = FALSE;
+ /* Make a pass to triangularize matrix. */
+ for (i=1; i < nknots - 1; ++i, ++ptr) {
+ if (fabs(ptr->diag) < EPS) {
+ /* Near zero on diagonal, pivot. */
+ if (fabs(ptr->upper) < EPS)
+ error(SINGERR, "");
+ flag = TRUE;
+ ptr->diag = i; /* Keep row index in diag.
+ Actual value of diag is always 1. */
+ if (i == nknots - 2) {
+ flag = 2;
+ /* Exchange next to last and last rows. */
+ k1 = ptr->rhs/ptr->upper;
+ if (fabs((ptr+1)->upper) < EPS)
+ error(SINGERR, "");
+ ptr->rhs = (ptr+1)->rhs/(ptr+1)->upper;
+ ptr->upper = (ptr+1)->diag/(ptr+1)->upper;
+ (ptr+1)->upper = 0.;
+ (ptr+1)->rhs = k1;
+ }
+ else {
+ ptr->rhs = (ptr+1)->rhs - (k1 = ptr->rhs/ptr->upper)*(ptr+1)->diag;
+ ptr->upper = (ptr+1)->upper; /* This isn't super-diagonal element
+ but rather one to its right.
+ Must watch for this when
+ back substituting. */
+ (++ptr)->diag = i-1;
+ ++i;
+ ptr->upper = 0;
+ ptr->rhs = k1;
+ (ptr+1)->rhs -= ptr->rhs;
+ }
+ }
+ else {
+ ptr->upper /= ptr->diag;
+ ptr->rhs /= ptr->diag;
+ ptr->diag = i-1; /* Used to reorder solution if needed. */
+ (ptr+1)->diag -= ptr->upper;
+ (ptr+1)->rhs -= ptr->rhs;
+ }
+ }
+ /* Last row is a special case. */
+ if (flag != 2) {
+ /* If flag == 2 last row is already computed. */
+ ptr->upper /= ptr->diag;
+ ptr->rhs /= ptr->diag;
+ ptr->diag = ptr - eqns;
+ ++ptr;
+ ptr->diag -= (ptr-1)->upper * ptr->upper;
+ ptr->rhs -= (ptr-1)->rhs * ptr->upper;
+ ptr->rhs /= ptr->diag;
+ ptr->diag = ptr - eqns;
+ }
+
+ /* Now make a pass back substituting for solution. */
+ --ptr;
+ for ( ; ptr >= eqns; --ptr) {
+ if ((int)ptr->diag != ptr - eqns) {
+ /* This row and one above have been exchanged in a pivot. */
+ --ptr;
+ ptr->rhs -= ptr->upper * (ptr+2)->rhs;
+ }
+ else
+ ptr->rhs -= ptr->upper * (ptr+1)->rhs;
+ }
+ if (flag) { /* Undo reordering done by pivoting. */
+ qsort(eqns, nknots, sizeof(struct bandm), fcompare);
+ }
+}
+
+/* fcompare -- Compare two floating point numbers. */
+fcompare(arg1, arg2)
+real *arg1, *arg2;
+{
+ if (arg1 > arg2)
+ return(1);
+ else if (arg1 < arg2)
+ return(-1);
+ else
+ return(0);
+}
+
+/* interpolate -- Do spline interpolation. */
+interpolate()
+{ int i;
+ struct pair *dp;
+ struct bandm *ep;
+ real h, xi, yi, hi, xu, xl, limit;
+
+ h = (xmax - xmin)/nint;
+ ep = eqns;
+ dp = data + 1;
+ for (xi = xmin; xi < xmax + 0.25*h; xi += h) {
+ while (dp->x < xi && dp < data + nknots - 1) {
+ ++dp; /* Skip to correct interval. */
+ ++ep;
+ }
+ if (dp < data + nknots - 1 && dp->x < xmax)
+ limit = dp->x;
+ else
+ limit = xmax;
+ for ( ; xi < limit - 0.25*h; xi += h) {
+ /* Do interpolation. */
+ hi = dp->x - (dp-1)->x;
+ xu = dp->x - xi;
+ xl = xi - (dp-1)->x;
+ yi = ((ep+1)->rhs*xl*xl/(6.*hi) + dp->y/hi - (ep+1)->rhs*hi/6.)*xl +
+ (ep->rhs*xu*xu/(6.*hi) + (dp-1)->y/hi - ep->rhs*hi/6.)*xu;
+ printf(OFMT, xi, yi);
+ }
+ if (limit != dp->x) { /* Interpolate. */
+ hi = dp->x - (dp-1)->x;
+ xu = dp->x - xmax;
+ xl = xmax - (dp-1)->x;
+ yi = ((ep+1)->rhs*xl*xl/(6.*hi) + dp->y/hi - (ep+1)->rhs*hi/6.)*xl +
+ (ep->rhs*xu*xu/(6.*hi) + (dp-1)->y/hi - ep->rhs*hi/6.)*xu;
+ printf(OFMT, xmax, yi);
+ }
+ else { /* Print knot. */
+ printf(OFMT, dp->x, dp->y);
+ xi = dp->x;
+ }
+ }
+}