GIStemp STEP1_EX_month

Overview

We will be looking at the EXTENSIONS/monthlydata C library in this section. I’ve chosen to leave the program listings as one large block rather than interleave comments. This is so that experienced programmers can just “see the code” and read it.

This is a very long library of functions complete with an extensive “make file” to install it into a production computer system. It’s well made and production quality; but don’t expect to just read it unless you have some decent programming experience. I don’t put much commentary in this page, it’s mostly just to let the curious see what’s in the library.

This program is complied by and run by “make” files in STEP1/EXTENSIONS/monthlydata directory. They are identical to the ones in the “stationstring” directory. Just remember that, though identical, this is a second copy in a second directory.

The Make Files

There are three of these, named “make_clean”, “make_shared”, and “Makefile.pre.in”. There is also a file named “Setup.in” in the same directory.

Here are The Make Files should you wish to see them.

The C program monthlydata.c

This program looks to me like a very well written set of stock library functions. I’m not going to put time into documenting them until the very end. It’s the broken bits I care about finding the most, not the well designed parts. The “good bits” you just compile and run.

My only complaint would be that there isn’t a companion document to tell you what each function is and what it is used for. But there seems to be no real documentaton with GIStemp at all.

Here is the listing. The explanation will follow some months or weeks from now below, after the === bar.

/* file monthlydata.c */

/* MonthlyData objects */

#include
#include "Python.h"

#define FEQUALS(x, y) (fabs((x) - (y)) ob_type == &MonthlyData_Type)

static MonthlyDataObject *
newMonthlyDataObject(double **data, const int years, const double bad,
		     const int begin, const int start, const int stop,
		     const int min)
{
    int m, s;
    MonthlyDataObject *self;
    self = PyObject_NEW(MonthlyDataObject, &MonthlyData_Type);
    if (self == NULL)
	return NULL;

    self->md_attr = NULL;
    self->years = years;
    self->bad = bad;
    self->begin = begin;
    self->start = start;
    self->stop = stop;
    self->min = min;

    for (m = 0; m data[m] = data[m];
	self->monthly_anoms[m] = (double *)PyMem_Malloc(years * sizeof(double));
    }

    for (s = 0; s seasonal_anoms[s] = (double *)PyMem_Malloc(years * sizeof(double));

    self->annual_anoms = (double *)PyMem_Malloc(years * sizeof(double));

    return self;
}

/* MonthlyDataObject methods */

static void
MonthlyData_dealloc(MonthlyDataObject *self)
{
    int m, s;
    for (m = 0; m data[m]);
	PyMem_Free((void *)self->monthly_anoms[m]);
    }

    for (s = 0; s seasonal_anoms[s]);
    }

    PyMem_Free((void *)self->annual_anoms);

    Py_XDECREF(self->md_attr);
    /* PyMem_DEL(self); */
}

staticforward void
compute_monthly(MonthlyDataObject *self);
staticforward void
compute_seasonal(MonthlyDataObject *self);
staticforward int
compute_annual(MonthlyDataObject *self);

static int
compute(MonthlyDataObject *self)
{
    int okay;
    self->computed_flag = 1;
    compute_monthly(self);
    compute_seasonal(self);
    okay = compute_annual(self);
    return okay;
}

static void
compute_monthly(MonthlyDataObject *self)
{
    int m;
    double bad = self->bad;

    for (m = 0; m data[m];
	double mean, *monthly_anoms_row;
	int n;
	for (n = 0; n years; ++n)
	{
	    int year = n + self->begin;
	    double datum = data_row[n];
	    if (year start || year > self->stop)
		continue;
	    else if (FEQUALS(datum, bad))
		continue;
	    else
	    {
		sum += datum;
		++wgt;
	    }
	}
	if (wgt > 0)
	    mean = sum / wgt;
	else
	    mean = bad;

	self->monthly_means[m] = mean;

	monthly_anoms_row = self->monthly_anoms[m];
	for (n = 0; n years; ++n)
	{
	    double datum;
	    if (FEQUALS(mean, bad))
	    {
		monthly_anoms_row[n] = self->bad;
		continue;
	    }
	    datum = data_row[n];
	    if (FEQUALS(datum, bad))
	    {
		monthly_anoms_row[n] = self->bad;
		continue;
	    }
	    monthly_anoms_row[n] = datum - mean;
	}
    }

}

static void
compute_seasonal(MonthlyDataObject *self)
{
    int seasons[4][3] = {
	{11,  0,  1},
	{ 2,  3,  4},
	{ 5,  6,  7},
	{ 8,  9, 10}
    };
    int s;
    double bad = self->bad;
    for (s = 0; s < 4; ++s) {
	int *months = seasons[s];
	double mean_sum = 0.0;
	int mean_wgt = 0;
	int i, n;
	double mean, *seasonal_anoms_row;
	for (i = 0; i monthly_means[m];
	    if (FEQUALS(monthly_mean, bad))
		continue;
	    mean_sum += monthly_mean;
	    ++mean_wgt;
	}
	mean = mean_wgt >= 2 ? mean_sum / mean_wgt : self->bad;
	self->seasonal_means[s] = mean;
	seasonal_anoms_row = self->seasonal_anoms[s];
	for (n = 0; n years; ++n) {
	    double anom_sum = 0.0;
	    int anom_wgt = 0;
	    double anom;
	    int i;
	    for (i = 0; i monthly_anoms[m][n - 1];
		}
		else
		    monthly_anom = self->monthly_anoms[m][n];
		if (FEQUALS(monthly_anom, bad))
		    continue;
		anom_sum += monthly_anom;
		++anom_wgt;
	    }
	    anom = anom_wgt >= 2 ? anom_sum / anom_wgt : self->bad;
	    seasonal_anoms_row[n] = anom;
	}
    }
}

static int
compute_annual(MonthlyDataObject *self)
{
    double mean_sum = 0.0;
    int mean_wgt = 0;
    int min = self->min;
    int count = 0;
    int s, n;
    double bad = self->bad;
    for (s = 0; s seasonal_means[s];
	if (FEQUALS(seasonal_mean, bad))
	    continue;
	mean_sum += seasonal_mean;
	++mean_wgt;
    }
    self->annual_mean = mean_wgt >= 3 ? mean_sum / mean_wgt : self->bad;
    for (n = 0; n years; ++n) {
	double anom_sum = 0.0;
	int anom_wgt = 0;
	double anom;
	for (s = 0; s seasonal_anoms[s][n];
	    if (FEQUALS(seasonal_anom, bad))
		continue;
	    anom_sum += seasonal_anom;
	    ++anom_wgt;
	}
	if (anom_wgt >= 3)
	{
	    anom = anom_sum / anom_wgt;
	    if (self->start begin &&
		n + self->begin stop)
		++count;
	}
	else
	    anom = bad;
	self->annual_anoms[n] = anom;
    }

/*      printf("count: %d min: %d\n", count, min); */
/*      fflush(stdout); */

    if (count < min)
    {
	return 0;
    }
    return 1;
}

static PyObject *
MonthlyData_monthly(MonthlyDataObject *self, PyObject *args)
{
    PyObject *pyanoms, *pymeans, *retval;
    int n, m;
    if (!PyArg_ParseTuple(args, ""))
	return NULL;
    pyanoms = PyList_New(12);
    pymeans = PyList_New(12);
    for (m = 0; m monthly_anoms[m];
	PyObject *pyrow = PyList_New(self->years);
	PyList_SetItem(pymeans, m, PyFloat_FromDouble(self->monthly_means[m]));
	for (n = 0; n years; ++n)
	    PyList_SetItem(pyrow, n, PyFloat_FromDouble(row[n]));
	PyList_SetItem(pyanoms, m, pyrow);
    }
    retval = Py_BuildValue("OO", pymeans, pyanoms);
    Py_DECREF(pymeans);
    Py_DECREF(pyanoms);
    return retval;
}

static PyObject *
MonthlyData_seasonal(MonthlyDataObject *self, PyObject *args)
{
    PyObject *pyanoms, *pymeans, *retval;
    int n, s;
    if (!PyArg_ParseTuple(args, ""))
	return NULL;
    pyanoms = PyList_New(4);
    pymeans = PyList_New(4);
    for (s = 0; s seasonal_anoms[s];
	PyObject *pyrow = PyList_New(self->years);
	PyList_SetItem(pymeans,s, PyFloat_FromDouble(self->seasonal_means[s]));
	for (n = 0; n years; ++n)
	    PyList_SetItem(pyrow, n, PyFloat_FromDouble(row[n]));
	PyList_SetItem(pyanoms, s, pyrow);
    }
    retval = Py_BuildValue("OO", pymeans, pyanoms);
    Py_DECREF(pymeans);
    Py_DECREF(pyanoms);
    return retval;
}

static PyObject *
MonthlyData_annual(MonthlyDataObject *self, PyObject *args)
{
    PyObject *pyanoms, *retval;
    int n;
    if (!PyArg_ParseTuple(args, ""))
	return NULL;
    pyanoms = PyList_New(self->years);
    for (n = 0; n years; ++n)
	PyList_SetItem(pyanoms, n, PyFloat_FromDouble(self->annual_anoms[n]));
    retval = Py_BuildValue("dO", self->annual_mean, pyanoms);
    Py_DECREF(pyanoms);
    return retval;
}

static PyObject *
MonthlyData_data(MonthlyDataObject *self, PyObject *args)
{
    PyObject *pydata = PyList_New(12);
    int m;
    if (pydata == NULL)
	return NULL;
    if (!PyArg_ParseTuple(args, ""))
	return NULL;
    for (m = 0; m years);
	double *row = self->data[m];
	int n;
	if (pyrow == NULL)
	    return NULL;
	for (n = 0; n years; ++n)
	    PyList_SetItem(pyrow, n, PyFloat_FromDouble(row[n]));
	PyList_SetItem(pydata, m, pyrow);
    }
    return pydata;
}

static PyObject *
MonthlyData_years(MonthlyDataObject *self, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ""))
	return NULL;
    return PyInt_FromLong((long)self->years);
}

static PyObject *
MonthlyData_data_years(MonthlyDataObject *self, PyObject *args)
{
    PyObject *pydata = MonthlyData_data(self, args);
    PyObject *retval = Py_BuildValue("Ol", pydata, (long)self->years);
    if (retval == NULL)
	return NULL;
    Py_DECREF(pydata);
    return retval;
}

static PyObject *
MonthlyData_begin(MonthlyDataObject *self, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ""))
	return NULL;
    return PyInt_FromLong((long)self->begin);
}

void
broken_line_regression(const double *list, const int years,
                       const int begin, const double bad,
                       int *x1_ptr, double *y1_ptr, int *x2_ptr,
		       double *y2_ptr, int *x3_ptr, double *y3_ptr,
		       double *m1_ptr, double *m2_ptr)
{
    int end = begin + years - 1;
    int actual_begin = 0;
    int actual_end = begin;
    int x, new_begin, new_end;
    int x1 = *x1_ptr;
    int x2 = *x2_ptr;
    int x3 = *x3_ptr;
    double y1 = *y1_ptr;
    double y2 = *y2_ptr;
    double y3 = *y3_ptr;
    double m1 = *m1_ptr;
    double m2 = *m2_ptr;

    int a = 0, b = 0, d = 0, e = 0, g = 0;
    double c = 0.0, f = 0.0, h = 0.0;

    for (x = begin; x <= end; ++x)
    {
	double y = list[x - begin];
	if (FEQUALS(y, bad))
	    continue;
	if (actual_begin == 0)
	    actual_begin = x;
	actual_end = x;
    }

    new_begin = actual_begin;
    new_end = actual_end;
    if (x1 < new_begin)
	x1 = new_begin;
    if (x2  new_end)
	x3 = new_end;
    if (x3 < x2)
    {
	PyErr_SetString(ErrorObject, "not enough data for this station");
	return;
    }

    for (x = x1; x <= x2 - 1; ++x)
    {
	double y = list[x - begin];
	int diff;
	if (FEQUALS(y, bad))
	    continue;
	diff = x - x2;
	a += diff*diff;
	b += diff;
	c += diff * y;
	h += y;
	++g;
    }
    for (x = x2; x years;
    begin = self->begin;
    end = years + begin - 1;
    anoms = self->annual_anoms;

    bad = self->bad;

    /*  initialize diff_sums, diff_wgts
     */
    diff_sums = (double *)malloc(years * sizeof(double));
    diff_wgts = (double *)malloc(years * sizeof(double));
    diff_means = (double *)malloc(years * sizeof(double));
    rur_means = (double *)malloc(years * sizeof(double));
    for (n = 0; n < years; ++n)
    {
	diff_sums[n] = 0.0;
	diff_wgts[n] = 0.0;
	diff_means[n] = bad;
	rur_means[n] = 0;
    }

    /*  compute diff_sums, diff_wgts
     */
    for (i = 0; i annual_anoms;
	int other_begin = other->begin;
	int other_years = other->years;
	int other_end = other_begin + other_years - 1;
	double other_bad = other->bad;

	int new_begin = begin >= other_begin ? begin : other_begin;
	int new_end = end <= other_end ? end : other_end;
	int new_years = new_end - new_begin + 1;

	int n;
	for (n = 0; n < new_years; ++n)
	{
	    int year = n + new_begin;
	    double y = anoms[year - begin];
	    double other_y;
	    if (FEQUALS(y, bad))
		continue;
	    other_y = other_anoms[year - other_begin];
	    if (FEQUALS(other_y, other_bad))
		continue;
	    diff_sums[year - begin] += (other_y - y)*weight;
	    diff_wgts[year - begin] += weight;
	    rur_means[year - begin] += other_y * weight;
	}
    }

    /*  compute diff_means
     */
    for (n = 0; n  0)
	    diff_means[n] = diff_sums[n] / diff_wgt;
    }

    /*  fit a broken line to diff_means
     */
    ax1 = x1;
    ax2 = x2;
    ax3 = x3;
    broken_line_regression(diff_means, years, begin, bad,
			   &ax1, &ay1, &ax2, &ay2, &ax3, &ay3, &am1, &am2);

    /*  check to see if an error occurred
     */
    if (PyErr_Occurred() != NULL)
    {
	PyMem_Free((void *)diff_sums);
	PyMem_Free((void *)diff_wgts);
	PyMem_Free((void *)diff_means);
	return NULL;
    }

    /*  determine beginning year of new data
     */
    old_ax1 = ax1;
    for (;;)
    {
	int n;
	new_begin = 9999;
	count = 0;
	for (n = ax1; n < ax2; ++n)
	    if (! FEQUALS(diff_means[n - begin], bad))
	    {
		++count;
		if (n = MAGIC_RATIO * (ax2 - ax1))
	{
	    new_begin = ax1;
	    break;
	}

	if (ax1 * 3 >= ax2 * 3 - 2 * (ax2 - old_ax1))
	{
	    new_begin = ax2;
	    break;
	}

	++ax1;
    }

    /*  determine end year for new data
     */
    {
	int count = 0;
	int n;
	for (n = ax2; n <= ax3; ++n)
	    if (! FEQUALS(diff_means[n - begin], bad))
		++count;
	if (count < MAGIC_RATIO * (ax3 - ax2 + 1))
	    new_end = ax3;
	else
	    new_end = end;
    }

    new_years = new_end - new_begin + 1;

    /*  create the list of rural averages
     */
    py_rur_avgs = PyList_New(new_years);
    for (n = 0; n  0)
	{
	    double datum = rur_means[year - begin] / wgt;
	    PyList_SetItem(py_rur_avgs, n, PyFloat_FromDouble(datum));
	}
	else
	    PyList_SetItem(py_rur_avgs, n, PyFloat_FromDouble(bad));
    }

    /*  initialize new data
     */
    for (m = 0; m < 12; ++m)
    {
	int n;
	new_data[m] = (double *)PyMem_Malloc(new_years * sizeof(double));
	for (n = 0; n data;
    for (n = 0; n <= new_years; ++n)
    {
	int year = n + new_begin;
	double diff = 9999;
	int m;

	if (year < ax1)
	    diff = ay1;
	else if (ax1 <= year && year <= ax2 - 1)
	    diff = am1*(year - ax2) + ay2;
	else if (ax2 <= year && year <= ax3)
	    diff = am2*(year - ax2) + ay2;
	else if (ax3 = 1)
	{
	    double dec_datum = data[11][year - 1 - begin];
	    new_data[11][n - 1] = dec_datum;
	    if (!FEQUALS(dec_datum, bad))
		new_data[11][n - 1] += diff;
	}

	if (n == new_years)
	    break;

	for (m = 0; m start, self->stop, self->min);
    compute(new_md_object);

    /*  cleanup diff_sums, diff_wgts, diff_means
     */
    PyMem_Free((void *)diff_sums);
    PyMem_Free((void *)diff_wgts);
    PyMem_Free((void *)diff_means);

    py_triple = Py_BuildValue("(id)(id)(id)", ax1, ay1, ax2, ay2, ax3, ay3);
    retval = Py_BuildValue("OOO", new_md_object, py_rur_avgs, py_triple);
    Py_DECREF(new_md_object);
    Py_DECREF(py_rur_avgs);
    Py_DECREF(py_triple);

    return retval;
}

static PyMethodDef MonthlyData_methods[] = {
	{"monthly",	(PyCFunction)MonthlyData_monthly,	1},
	{"seasonal",	(PyCFunction)MonthlyData_seasonal,	1},
	{"annual",	(PyCFunction)MonthlyData_annual,	1},
	{"data",	(PyCFunction)MonthlyData_data, 1},
	{"years",	(PyCFunction)MonthlyData_years, 1},
	{"data_years",	(PyCFunction)MonthlyData_data_years, 1},
	{"begin",	(PyCFunction)MonthlyData_begin, 1},
	{"homogenize",  (PyCFunction)MonthlyData_homogenize, 1},
	{NULL,		NULL}		/* sentinel */
};

static PyObject *
MonthlyData_getattr(MonthlyDataObject *self, char *name)
{
    if (self->md_attr != NULL) {
	PyObject *v = PyDict_GetItemString(self->md_attr, name);
	if (v != NULL) {
	    Py_INCREF(v);
	    return v;
	}
    }
    return Py_FindMethod(MonthlyData_methods, (PyObject *)self, name);
}

static int
MonthlyData_setattr(MonthlyDataObject *self, char *name, PyObject *v)
{
    if (self->md_attr == NULL) {
	self->md_attr = PyDict_New();
	if (self->md_attr == NULL)
	    return -1;
    }
    if (v == NULL) {
	int rv = PyDict_DelItemString(self->md_attr, name);
	if (rv md_attr, name, v);
}

/* --------------------------------------------------------------------- */
staticforward PyTypeObject MonthlyData_Type = {
	PyObject_HEAD_INIT(&PyType_Type)
	0,			/*ob_size*/
	"MonthlyData",			/*tp_name*/
	sizeof(MonthlyDataObject),	/*tp_basicsize*/
	0,			/*tp_itemsize*/
	/* methods */
	(destructor)MonthlyData_dealloc, /*tp_dealloc*/
	0,			/*tp_print*/
	(getattrfunc)MonthlyData_getattr, /*tp_getattr*/
	(setattrfunc)MonthlyData_setattr, /*tp_setattr*/
	0,			/*tp_compare*/
	0,			/*tp_repr*/
	0,			/*tp_as_number*/
	0,			/*tp_as_sequence*/
	0,			/*tp_as_mapping*/
	0,			/*tp_hash*/
};
/* --------------------------------------------------------------------- */

/* Function of several arguments returning new MonthlyData object */

static PyObject *
monthlydata_new(PyObject *self, PyObject *args)
{
	MonthlyDataObject *rv;
	PyObject *pydata;
	int years, begin, start, stop, min, m, n;
	int tmp_start, tmp_stop;
	double bad = 999.9;
	double *data[12];
	double *monthly;
	int end;
	int okay = 1;

	begin = start = stop = 0;
	min = 0;
	if (!PyArg_ParseTuple(args, "O|diiii", &pydata, &bad,
	    &begin, &start, &stop, &min))
	    return NULL;
	if (!PyList_Check(pydata))
	    return NULL;
	years = PyList_Size(PyList_GetItem(pydata, 0));
	if (years < min)
	{
	    PyErr_SetString(ErrorObject, "not enough data for this station");
	    return NULL;
	}
	end = begin + years - 1;
	tmp_start = start;
	tmp_stop = stop;
	if (start  end)
	    tmp_stop = end;
	if (tmp_stop - tmp_start + 1 < min)
	{
	    PyErr_SetString(ErrorObject, "not enough data for this station");
	    return NULL;
	}

	if (start == 0 && stop == 0)
	{
	    start = begin;
	    stop = end;
	}

	for (m = 0; m < 12; ++m)
	{
	    PyObject *pymonthly = PyList_GetItem(pydata, m);
	    monthly = (double *)PyMem_Malloc(years * sizeof(double));
	    for (n = 0; n < years; ++n)
		monthly[n] = PyFloat_AsDouble(PyList_GetItem(pymonthly, n));
	    data[m] = monthly;
	}

	rv = newMonthlyDataObject(data, years, bad, begin, start, stop, min);
	if (rv == NULL)
	    return NULL;

	okay = compute(rv);
	if (!okay)
	{
	    Py_XDECREF(rv);
	    PyErr_SetString(ErrorObject, "not enough data for this station");
	    return NULL;
	}

	return (PyObject *)rv;
}

static PyObject *
monthlydata_fit_broken_line(PyObject *self, PyObject *args)
{
    int x1 = 1890;
    int x2 = 1950;
    int x3 = 1980;
    int begin;
    int ax1, ax2, ax3;
    double ay1, ay2, ay3, am1, am2;
    double *ann_means;
    int years, n;
    double bad;
    PyObject *py_ann_anoms;
    double ann_mean;
    int new_years, new_begin;

    PyObject *retval;
    if (!PyArg_ParseTuple(args, "Oddiiii", &py_ann_anoms, &ann_mean, &bad,
			  &begin, &x1, &x2, &x3))
	return NULL;
    if (!PyList_Check(py_ann_anoms))
	return NULL;
    if (FEQUALS(ann_mean, bad))
    {
	PyErr_SetString(ErrorObject, "not enough data for this station");
	return NULL;
    }
    ax1 = x1;
    ax2 = x2;
    ax3 = x3;
    years = PyList_Size(py_ann_anoms);
    new_years = x3 - x1 + 1;
    new_begin = x1;

    ann_means = (double *)PyMem_Malloc(new_years * sizeof(double));

    for (n = 0; n < years; ++n)
    {
	double anom = PyFloat_AsDouble(PyList_GetItem(py_ann_anoms, n));
	int year = n + begin;
	if ((year < x1) || (x3 < year))
	    continue;
	if (! FEQUALS(anom, bad))
	    ann_means[year - new_begin] = anom + ann_mean;
	else
	    ann_means[year - new_begin] = bad;
    }

    broken_line_regression(ann_means, new_years, new_begin, bad,
			   &ax1, &ay1, &ax2, &ay2, &ax3, &ay3, &am1, &am2);

    PyMem_Free((void *)ann_means);
    retval = Py_BuildValue("((id)(id)(id))", ax1, ay1, ax2, ay2, ax3, ay3);
    return retval;
}

/* List of functions defined in the module */

static PyMethodDef monthlydata_methods[] = {
	{"new",		monthlydata_new,		1},
	{"fit_broken_line", monthlydata_fit_broken_line, 1},
	{NULL,		NULL}		/* sentinel */
};

/* Initialization function for the module (*must* be called initxx) */

void
initmonthlydata()
{
    PyObject *m, *d;

    /* Create the module and add the functions */
    m = Py_InitModule("monthlydata", monthlydata_methods);

    /* Add some symbolic constants to the module */
    d = PyModule_GetDict(m);
    ErrorObject = PyErr_NewException("monthlydata.error", NULL, NULL);
    PyDict_SetItemString(d, "error", ErrorObject);
}

=========================================================

The analysis of this program will have to wait a fair while as I’m still finishing another step. It looks like it’s a well done library of utilities so I’ll likely leave it to the end.

Advertisements

About E.M.Smith

A technical managerial sort interested in things from Stonehenge to computer science. My present "hot buttons' are the mythology of Climate Change and ancient metrology; but things change...
This entry was posted in GISStemp Technical and Source Code and tagged , , , , , . Bookmark the permalink.

3 Responses to GIStemp STEP1_EX_month

  1. Dan Hughes says:

    E. M. I have sent you e-mail about my attempt to get GISSTemp operational.

    I need some assistance with Python installation for STEP1.

    Thanks

    Dan

  2. E.M.Smith says:

    Hi Dan!

    I was in one of those focused world blocked out coding fenzies (as you can tell by all the pages that suddenly popped up here!) to build this source code documentations pages. I’ve had a few hours sleep now (after a couple of all nighters…).

    What kind of platform are you installing on? I have Mac, Linux, and can make a FreeBSD if needed. My Windows box is, er, old and crusty with no language kits…

    What problem are you hitting?

  3. E.M.Smith says:

    It looks like Macs don’t have a C compiler already installed. One can be downloaded from Apple for free, but you need to get a “free” account to do it. It’s part of the xcode bundle.

    http://developer.apple.com/technology/xcode.html

    These folks seem to have pointers to both FORTRAN and gcc for Macs:

    http://hpc.sourceforge.net/

    And this looks like a free gcc download:

    http://sourceforge.net/projects/gdcmac

    (All because Linux comes with gcc and I don’t know what you do for Windows…)

Comments are closed.