/*
 * This file is part of tela the Tensor Language.
 * Copyright (c) 1994-1996 Pekka Janhunen
 */

/*
  fftpack.c : A set of FFT routines in C.
  Algorithmically based on Fortran-77 FFTPACK by Paul N. Swarztrauber (Version 4, 1985).

  Compilation outside Tela: cc -DSTANDALONE fftpack.c.
  If you don't define STANDALONE it tries to include "deftyp.H".
  
  This file is also C++ compatible.
  
  Pekka Janhunen 23.2.1995
*/

/* isign is +1 for backward and -1 for forward transforms */

#include <math.h>
#include <stdio.h>

#ifdef STANDALONE
#  define Treal double
#  define Tint int
#else
#  include "deftyp.h"
#endif

#define ref(u,a) u[a]

#define MAXFAC 13		/* maximum number of factors in factorization of n */

#ifdef __cplusplus
extern "C" {
#endif
	
/* ----------------------------------------------------------------------
   passf2, passf3, passf4, passf5, passf. Complex FFT passes fwd and bwd.
   ---------------------------------------------------------------------- */
	
static void passf2(Tint ido, Tint l1, const Treal cc[], Treal ch[], const Treal wa1[], int isign)
/* isign==+1 for backward transform */
{
    Tint i, k, ah, ac;
    Treal ti2, tr2;
    if (ido <= 2) {
		for (k=0; k<l1; k++) {
			ah = k*ido;
			ac = 2*k*ido;
			ch[ah]              = ref(cc,ac) + ref(cc,ac + ido);
			ch[ah + ido*l1]     = ref(cc,ac) - ref(cc,ac + ido);
			ch[ah+1]            = ref(cc,ac+1) + ref(cc,ac + ido + 1);
			ch[ah + ido*l1 + 1] = ref(cc,ac+1) - ref(cc,ac + ido + 1);
		}
	} else {
		for (k=0; k<l1; k++) {
			for (i=0; i<ido-1; i+=2) {
				ah = i + k*ido;
				ac = i + 2*k*ido;
				ch[ah]   = ref(cc,ac) + ref(cc,ac + ido);
				tr2      = ref(cc,ac) - ref(cc,ac + ido);
				ch[ah+1] = ref(cc,ac+1) + ref(cc,ac + 1 + ido);
				ti2      = ref(cc,ac+1) - ref(cc,ac + 1 + ido);
				ch[ah+l1*ido+1] = wa1[i]*ti2 + isign*wa1[i+1]*tr2;
				ch[ah+l1*ido]   = wa1[i]*tr2 - isign*wa1[i+1]*ti2;
			}
		}
	}
} /* passf2 */


static void passf3(Tint ido, Tint l1, const Treal cc[], Treal ch[], 
				   const Treal wa1[], const Treal wa2[], int isign)
/* isign==+1 for backward transform */
{
    static const Treal taur = -0.5;
    static const Treal taui = 0.866025403784439;
    Tint i, k, ac, ah;
    Treal ci2, ci3, di2, di3, cr2, cr3, dr2, dr3, ti2, tr2;
    if (ido == 2) {
		for (k=1; k<=l1; k++) {
			ac = (3*k - 2)*ido;
			tr2 = ref(cc,ac) + ref(cc,ac + ido);
			cr2 = ref(cc,ac - ido) + taur*tr2;
			ah = (k - 1)*ido;
			ch[ah] = ref(cc,ac - ido) + tr2;

			ti2 = ref(cc,ac + 1) + ref(cc,ac + ido + 1);
			ci2 = ref(cc,ac - ido + 1) + taur*ti2;
			ch[ah + 1] = ref(cc,ac - ido + 1) + ti2;

			cr3 = isign*taui*(ref(cc,ac) - ref(cc,ac + ido));
			ci3 = isign*taui*(ref(cc,ac + 1) - ref(cc,ac + ido + 1));
			ch[ah + l1*ido] = cr2 - ci3;
			ch[ah + 2*l1*ido] = cr2 + ci3;
			ch[ah + l1*ido + 1] = ci2 + cr3;
			ch[ah + 2*l1*ido + 1] = ci2 - cr3;
		}
	} else {
		for (k=1; k<=l1; k++) {
			for (i=0; i<ido-1; i+=2) {
				ac = i + (3*k - 2)*ido;
				tr2 = ref(cc,ac) + ref(cc,ac + ido);
				cr2 = ref(cc,ac - ido) + taur*tr2;
				ah = i + (k-1)*ido;
				ch[ah] = ref(cc,ac - ido) + tr2;
				ti2 = ref(cc,ac + 1) + ref(cc,ac + ido + 1);
				ci2 = ref(cc,ac - ido + 1) + taur*ti2;
				ch[ah + 1] = ref(cc,ac - ido + 1) + ti2;
				cr3 = isign*taui*(ref(cc,ac) - ref(cc,ac + ido));
				ci3 = isign*taui*(ref(cc,ac + 1) - ref(cc,ac + ido + 1));
				dr2 = cr2 - ci3;
				dr3 = cr2 + ci3;
				di2 = ci2 + cr3;
				di3 = ci2 - cr3;
				ch[ah + l1*ido + 1] = wa1[i]*di2 + isign*wa1[i+1]*dr2;
				ch[ah + l1*ido] = wa1[i]*dr2 - isign*wa1[i+1]*di2;
				ch[ah + 2*l1*ido + 1] = wa2[i]*di3 + isign*wa2[i+1]*dr3;
				ch[ah + 2*l1*ido] = wa2[i]*dr3 - isign*wa2[i+1]*di3;
			}
		}
	}
} /* passf3 */


static void passf4(Tint ido, Tint l1, const Treal cc[], Treal ch[], 
				   const Treal wa1[], const Treal wa2[], const Treal wa3[], int isign)
/* isign == -1 for forward transform and +1 for backward transform */
{
    Tint i, k, ac, ah;
    Treal ci2, ci3, ci4, cr2, cr3, cr4, ti1, ti2, ti3, ti4, tr1, tr2, tr3, tr4;
    if (ido == 2) {
		for (k=0; k<l1; k++) {
			ac = 4*k*ido + 1;
			ti1 = ref(cc,ac) - ref(cc,ac + 2*ido);
			ti2 = ref(cc,ac) + ref(cc,ac + 2*ido);
			tr4 = ref(cc,ac + 3*ido) - ref(cc,ac + ido);
			ti3 = ref(cc,ac + ido) + ref(cc,ac + 3*ido);
			tr1 = ref(cc,ac - 1) - ref(cc,ac + 2*ido - 1);
			tr2 = ref(cc,ac - 1) + ref(cc,ac + 2*ido - 1);
			ti4 = ref(cc,ac + ido - 1) - ref(cc,ac + 3*ido - 1);
			tr3 = ref(cc,ac + ido - 1) + ref(cc,ac + 3*ido - 1);
			ah = k*ido;
			ch[ah] = tr2 + tr3;
			ch[ah + 2*l1*ido] = tr2 - tr3;
			ch[ah + 1] = ti2 + ti3;
			ch[ah + 2*l1*ido + 1] = ti2 - ti3;
			ch[ah + l1*ido] = tr1 + isign*tr4;
			ch[ah + 3*l1*ido] = tr1 - isign*tr4;
			ch[ah + l1*ido + 1] = ti1 + isign*ti4;
			ch[ah + 3*l1*ido + 1] = ti1 - isign*ti4;
		}
	} else {
		for (k=0; k<l1; k++) {
			for (i=0; i<ido-1; i+=2) {
				ac = i + 1 + 4*k*ido;
				ti1 = ref(cc,ac) - ref(cc,ac + 2*ido);
				ti2 = ref(cc,ac) + ref(cc,ac + 2*ido);
				ti3 = ref(cc,ac + ido) + ref(cc,ac + 3*ido);
				tr4 = ref(cc,ac + 3*ido) - ref(cc,ac + ido);
				tr1 = ref(cc,ac - 1) - ref(cc,ac + 2*ido - 1);
				tr2 = ref(cc,ac - 1) + ref(cc,ac + 2*ido - 1);
				ti4 = ref(cc,ac + ido - 1) - ref(cc,ac + 3*ido - 1);
				tr3 = ref(cc,ac + ido - 1) + ref(cc,ac + 3*ido - 1);
				ah = i + k*ido;
				ch[ah] = tr2 + tr3;
				cr3 = tr2 - tr3;
				ch[ah + 1] = ti2 + ti3;
				ci3 = ti2 - ti3;
				cr2 = tr1 + isign*tr4;
				cr4 = tr1 - isign*tr4;
				ci2 = ti1 + isign*ti4;
				ci4 = ti1 - isign*ti4;
				ch[ah + l1*ido] = wa1[i]*cr2 - isign*wa1[i + 1]*ci2;
				ch[ah + l1*ido + 1] = wa1[i]*ci2 + isign*wa1[i + 1]*cr2;
				ch[ah + 2*l1*ido] = wa2[i]*cr3 - isign*wa2[i + 1]*ci3;
				ch[ah + 2*l1*ido + 1] = wa2[i]*ci3 + isign*wa2[i + 1]*cr3;
				ch[ah + 3*l1*ido] = wa3[i]*cr4 -isign*wa3[i + 1]*ci4;
				ch[ah + 3*l1*ido + 1] = wa3[i]*ci4 + isign*wa3[i + 1]*cr4;
			}
		}
	}
} /* passf4 */


static void passf5(Tint ido, Tint l1, const Treal cc[], Treal ch[], 
				   const Treal wa1[], const Treal wa2[], const Treal wa3[], const Treal wa4[], int isign)
/* isign == -1 for forward transform and +1 for backward transform */
{
    static const Treal tr11 = 0.309016994374947;
    static const Treal ti11 = 0.951056516295154;
    static const Treal tr12 = -0.809016994374947;
    static const Treal ti12 = 0.587785252292473;
    Tint i, k, ac, ah;
    Treal ci2, ci3, ci4, ci5, di3, di4, di5, di2, cr2, cr3, cr5, cr4, ti2, ti3,
	     ti4, ti5, dr3, dr4, dr5, dr2, tr2, tr3, tr4, tr5;
    if (ido == 2) {
		for (k = 1; k <= l1; ++k) {
			ac = (5*k - 4)*ido + 1;
			ti5 = ref(cc,ac) - ref(cc,ac + 3*ido);
			ti2 = ref(cc,ac) + ref(cc,ac + 3*ido);
			ti4 = ref(cc,ac + ido) - ref(cc,ac + 2*ido);
			ti3 = ref(cc,ac + ido) + ref(cc,ac + 2*ido);
			tr5 = ref(cc,ac - 1) - ref(cc,ac + 3*ido - 1);
			tr2 = ref(cc,ac - 1) + ref(cc,ac + 3*ido - 1);
			tr4 = ref(cc,ac + ido - 1) - ref(cc,ac + 2*ido - 1);
			tr3 = ref(cc,ac + ido - 1) + ref(cc,ac + 2*ido - 1);
			ah = (k - 1)*ido;
			ch[ah] = ref(cc,ac - ido - 1) + tr2 + tr3;
			ch[ah + 1] = ref(cc,ac - ido) + ti2 + ti3;
			cr2 = ref(cc,ac - ido - 1) + tr11*tr2 + tr12*tr3;
			ci2 = ref(cc,ac - ido) + tr11*ti2 + tr12*ti3;
			cr3 = ref(cc,ac - ido - 1) + tr12*tr2 + tr11*tr3;
			ci3 = ref(cc,ac - ido) + tr12*ti2 + tr11*ti3;
			cr5 = isign*(ti11*tr5 + ti12*tr4);
			ci5 = isign*(ti11*ti5 + ti12*ti4);
			cr4 = isign*(ti12*tr5 - ti11*tr4);
			ci4 = isign*(ti12*ti5 - ti11*ti4);
			ch[ah + l1*ido] = cr2 - ci5;
			ch[ah + 4*l1*ido] = cr2 + ci5;
			ch[ah + l1*ido + 1] = ci2 + cr5;
			ch[ah + 2*l1*ido + 1] = ci3 + cr4;
			ch[ah + 2*l1*ido] = cr3 - ci4;
			ch[ah + 3*l1*ido] = cr3 + ci4;
			ch[ah + 3*l1*ido + 1] = ci3 - cr4;
			ch[ah + 4*l1*ido + 1] = ci2 - cr5;
		}
	} else {
		for (k=1; k<=l1; k++) {
			for (i=0; i<ido-1; i+=2) {
				ac = i + 1 + (k*5 - 4)*ido;
				ti5 = ref(cc,ac) - ref(cc,ac + 3*ido);
				ti2 = ref(cc,ac) + ref(cc,ac + 3*ido);
				ti4 = ref(cc,ac + ido) - ref(cc,ac + 2*ido);
				ti3 = ref(cc,ac + ido) + ref(cc,ac + 2*ido);
				tr5 = ref(cc,ac - 1) - ref(cc,ac + 3*ido - 1);
				tr2 = ref(cc,ac - 1) + ref(cc,ac + 3*ido - 1);
				tr4 = ref(cc,ac + ido - 1) - ref(cc,ac + 2*ido - 1);
				tr3 = ref(cc,ac + ido - 1) + ref(cc,ac + 2*ido - 1);
				ah = i + (k - 1)*ido;
				ch[ah] = ref(cc,ac - ido - 1) + tr2 + tr3;
				ch[ah + 1] = ref(cc,ac - ido) + ti2 + ti3;
				cr2 = ref(cc,ac - ido - 1) + tr11*tr2 + tr12*tr3;

				ci2 = ref(cc,ac - ido) + tr11*ti2 + tr12*ti3;
				cr3 = ref(cc,ac - ido - 1) + tr12*tr2 + tr11*tr3;

				ci3 = ref(cc,ac - ido) + tr12*ti2 + tr11*ti3;
				cr5 = isign*(ti11*tr5 + ti12*tr4);
				ci5 = isign*(ti11*ti5 + ti12*ti4);
				cr4 = isign*(ti12*tr5 - ti11*tr4);
				ci4 = isign*(ti12*ti5 - ti11*ti4);
				dr3 = cr3 - ci4;
				dr4 = cr3 + ci4;
				di3 = ci3 + cr4;
				di4 = ci3 - cr4;
				dr5 = cr2 + ci5;
				dr2 = cr2 - ci5;
				di5 = ci2 - cr5;
				di2 = ci2 + cr5;
				ch[ah + l1*ido] = wa1[i]*dr2 - isign*wa1[i+1]*di2;
				ch[ah + l1*ido + 1] = wa1[i]*di2 + isign*wa1[i+1]*dr2;
				ch[ah + 2*l1*ido] = wa2[i]*dr3 - isign*wa2[i+1]*di3;
				ch[ah + 2*l1*ido + 1] = wa2[i]*di3 + isign*wa2[i+1]*dr3;
				ch[ah + 3*l1*ido] = wa3[i]*dr4 - isign*wa3[i+1]*di4;
				ch[ah + 3*l1*ido + 1] = wa3[i]*di4 + isign*wa3[i+1]*dr4;
				ch[ah + 4*l1*ido] = wa4[i]*dr5 - isign*wa4[i+1]*di5;
				ch[ah + 4*l1*ido + 1] = wa4[i]*di5 + isign*wa4[i+1]*dr5;
			}
		}
	}
} /* passf5 */


static void passf(Tint *nac, Tint ido, Tint ip, Tint l1, Tint idl1,
				  Treal cc[], Treal ch[],
				  const Treal wa[], int isign)
/* isign is -1 for forward transform and +1 for backward transform */
{
    Tint idij, idlj, idot, ipph, i, j, k, l, jc, lc, ik, nt, idj, idl, inc,idp;
    Treal wai, war;

    idot = ido / 2;
    nt = ip*idl1;
    ipph = (ip + 1) / 2;
    idp = ip*ido;
    if (ido >= l1) {
		for (j=1; j<ipph; j++) {
			jc = ip - j;
			for (k=0; k<l1; k++) {
				for (i=0; i<ido; i++) {
					ch[i + (k + j*l1)*ido] =
						ref(cc,i + (j + k*ip)*ido) + ref(cc,i + (jc + k*ip)*ido);
					ch[i + (k + jc*l1)*ido] =
						ref(cc,i + (j + k*ip)*ido) - ref(cc,i + (jc + k*ip)*ido);
				}
			}
		}
		for (k=0; k<l1; k++)
			for (i=0; i<ido; i++)
				ch[i + k*ido] = ref(cc,i + k*ip*ido);
	} else {
		for (j=1; j<ipph; j++) {
			jc = ip - j;
			for (i=0; i<ido; i++) {
				for (k=0; k<l1; k++) {
					ch[i + (k + j*l1)*ido] = ref(cc,i + (j + k*ip)*ido) + ref(cc,i + (jc + k*ip)*ido);
					ch[i + (k + jc*l1)*ido] = ref(cc,i + (j + k*ip)*ido) - ref(cc,i + (jc + k*ip)*ido);
				}
			}
		}
		for (i=0; i<ido; i++)
			for (k=0; k<l1; k++)
				ch[i + k*ido] = ref(cc,i + k*ip*ido);
	}
	
	idl = 2 - ido;
    inc = 0;
    for (l=1; l<ipph; l++) {
		lc = ip - l;
		idl += ido;
		for (ik=0; ik<idl1; ik++) {
			cc[ik + l*idl1] = ch[ik] + wa[idl - 2]*ch[ik + idl1];
			cc[ik + lc*idl1] = isign*wa[idl-1]*ch[ik + (ip-1)*idl1];
		}
		idlj = idl;
		inc += ido;
		for (j=2; j<ipph; j++) {
			jc = ip - j;
			idlj += inc;
			if (idlj > idp) idlj -= idp;
			war = wa[idlj - 2];
			wai = wa[idlj-1];
			for (ik=0; ik<idl1; ik++) {
				cc[ik + l*idl1] += war*ch[ik + j*idl1];
				cc[ik + lc*idl1] += isign*wai*ch[ik + jc*idl1];
			}
		}
    }
    for (j=1; j<ipph; j++)
		for (ik=0; ik<idl1; ik++)
			ch[ik] += ch[ik + j*idl1];
    for (j=1; j<ipph; j++) {
		jc = ip - j;
		for (ik=1; ik<idl1; ik+=2) {
			ch[ik - 1 + j*idl1] = cc[ik - 1 + j*idl1] - cc[ik + jc*idl1];
			ch[ik - 1 + jc*idl1] = cc[ik - 1 + j*idl1] + cc[ik + jc*idl1];
			ch[ik + j*idl1] = cc[ik + j*idl1] + cc[ik - 1 + jc*idl1];
			ch[ik + jc*idl1] = cc[ik + j*idl1] - cc[ik - 1 + jc*idl1];
		}
    }
    *nac = 1;
    if (ido == 2) return;
    *nac = 0;
    for (ik=0; ik<idl1; ik++)
		cc[ik] = ch[ik];
    for (j=1; j<ip; j++) {
		for (k=0; k<l1; k++) {
			cc[(k + j*l1)*ido + 0] = ch[(k + j*l1)*ido + 0];
			cc[(k + j*l1)*ido + 1] = ch[(k + j*l1)*ido + 1];
		}
    }
    if (idot <= l1) {
		idij = 0;
		for (j=1; j<ip; j++) {
			idij += 2;
			for (i=3; i<ido; i+=2) {
				idij += 2;
				for (k=0; k<l1; k++) {
					cc[i - 1 + (k + j*l1)*ido] =
						wa[idij - 2]*ch[i - 1 + (k + j*l1)*ido] -
						isign*wa[idij-1]*ch[i + (k + j*l1)*ido];
					cc[i + (k + j*l1)*ido] =
						wa[idij - 2]*ch[i + (k + j*l1)*ido] +
						isign*wa[idij-1]*ch[i - 1 + (k + j*l1)*ido];
				}
			}
		}
	} else {
		idj = 2 - ido;
		for (j=1; j<ip; j++) {
			idj += ido;
			for (k = 0; k < l1; k++) {
				idij = idj;
				for (i=3; i<ido; i+=2) {
					idij += 2;
					cc[i - 1 + (k + j*l1)*ido] =
						wa[idij - 2]*ch[i - 1 + (k + j*l1)*ido] -
						isign*wa[idij-1]*ch[i + (k + j*l1)*ido];
					cc[i + (k + j*l1)*ido] =
						wa[idij - 2]*ch[i + (k + j*l1)*ido] +
						isign*wa[idij-1]*ch[i - 1 + (k + j*l1)*ido];
				}
			}
		}
	}
} /* passf */


/* ----------------------------------------------------------------------
   radf2,radb2, radf3,radb3, radf4,radb4, radf5,radb5, radfg,radbg.
   Real FFT passes fwd and bwd.
   ---------------------------------------------------------------------- */

static void radf2(Tint ido, Tint l1, const Treal cc[], Treal ch[], const Treal wa1[])
{
    Tint i, k, ic;
    Treal ti2, tr2;
    for (k=0; k<l1; k++) {
		ch[2*k*ido] =
			ref(cc,k*ido) + ref(cc,(k + l1)*ido);
		ch[(2*k+1)*ido + ido-1] =
			ref(cc,k*ido) - ref(cc,(k + l1)*ido);
    }
    if (ido < 2) return;
	if (ido != 2) {
		for (k=0; k<l1; k++) {
			for (i=2; i<ido; i+=2) {
				ic = ido - i;
				tr2 = wa1[i - 2]*ref(cc, i-1 + (k + l1)*ido) + wa1[i - 1]*ref(cc, i + (k + l1)*ido);
				ti2 = wa1[i - 2]*ref(cc, i + (k + l1)*ido) - wa1[i - 1]*ref(cc, i-1 + (k + l1)*ido);
				ch[i + 2*k*ido] = ref(cc,i + k*ido) + ti2;
				ch[ic + (2*k+1)*ido] = ti2 - ref(cc,i + k*ido);
				ch[i - 1 + 2*k*ido] = ref(cc,i - 1 + k*ido) + tr2;
				ch[ic - 1 + (2*k+1)*ido] = ref(cc,i - 1 + k*ido) - tr2;
			}
		}
		if (ido % 2 == 1) return;
	}
	for (k=0; k<l1; k++) {
		ch[(2*k+1)*ido] = -ref(cc,ido-1 + (k + l1)*ido);
		ch[ido-1 + 2*k*ido] = ref(cc,ido-1 + k*ido);
	}
} /* radf2 */


static void radb2(Tint ido, Tint l1, const Treal cc[], Treal ch[], const Treal wa1[])
{
    Tint i, k, ic;
    Treal ti2, tr2;
    for (k=0; k<l1; k++) {
		ch[k*ido] =
			ref(cc,2*k*ido) + ref(cc,ido-1 + (2*k+1)*ido);
		ch[(k + l1)*ido] =
			ref(cc,2*k*ido) - ref(cc,ido-1 + (2*k+1)*ido);
    }
    if (ido < 2) return;
    if (ido != 2) {
		for (k = 0; k < l1; ++k) {
			for (i = 2; i < ido; i += 2) {
				ic = ido - i;
				ch[i-1 + k*ido] =
					ref(cc,i-1 + 2*k*ido) + ref(cc,ic-1 + (2*k+1)*ido);
				tr2 = ref(cc,i-1 + 2*k*ido) - ref(cc,ic-1 + (2*k+1)*ido);
				ch[i + k*ido] =
					ref(cc,i + 2*k*ido) - ref(cc,ic + (2*k+1)*ido);
				ti2 = ref(cc,i + (2*k)*ido) + ref(cc,ic + (2*k+1)*ido);
				ch[i-1 + (k + l1)*ido] =
					wa1[i - 2]*tr2 - wa1[i - 1]*ti2;
				ch[i + (k + l1)*ido] =
					wa1[i - 2]*ti2 + wa1[i - 1]*tr2;
			}
		}
		if (ido % 2 == 1) return;
	}
    for (k = 0; k < l1; k++) {
		ch[ido-1 + k*ido] = 2*ref(cc,ido-1 + 2*k*ido);
		ch[ido-1 + (k + l1)*ido] = -2*ref(cc,(2*k+1)*ido);
    }
} /* radb2 */


static void radf3(Tint ido, Tint l1, const Treal cc[], Treal ch[], 
				  const Treal wa1[], const Treal wa2[])
{
    static const Treal taur = -0.5;
    static const Treal taui = 0.866025403784439;
    Tint i, k, ic;
    Treal ci2, di2, di3, cr2, dr2, dr3, ti2, ti3, tr2, tr3;
    for (k=0; k<l1; k++) {
		cr2 = ref(cc,(k + l1)*ido) + ref(cc,(k + 2*l1)*ido);
		ch[3*k*ido] = ref(cc,k*ido) + cr2;
		ch[(3*k+2)*ido] = taui*(ref(cc,(k + l1*2)*ido) - ref(cc,(k + l1)*ido));
		ch[ido-1 + (3*k + 1)*ido] = ref(cc,k*ido) + taur*cr2;
    }
    if (ido == 1) return;
    for (k=0; k<l1; k++) {
		for (i=2; i<ido; i+=2) {
			ic = ido - i;
			dr2 = wa1[i - 2]*ref(cc,i - 1 + (k + l1)*ido) + 
				wa1[i - 1]*ref(cc,i + (k + l1)*ido);
			di2 = wa1[i - 2]*ref(cc,i + (k + l1)*ido) - wa1[i - 1]*ref(cc,i - 1 + (k + l1)*ido);
			dr3 = wa2[i - 2]*ref(cc,i - 1 + (k + l1*2)*ido) + wa2[i - 1]*ref(cc,i + (k + l1*2)*ido);
			di3 = wa2[i - 2]*ref(cc,i + (k + l1*2)*ido) - wa2[i - 1]*ref(cc,i - 1 + (k + l1*2)*ido);
			cr2 = dr2 + dr3;
			ci2 = di2 + di3;
			ch[i - 1 + 3*k*ido] = ref(cc,i - 1 + k*ido) + cr2;
			ch[i + 3*k*ido] = ref(cc,i + k*ido) + ci2;
			tr2 = ref(cc,i - 1 + k*ido) + taur*cr2;
			ti2 = ref(cc,i + k*ido) + taur*ci2;
			tr3 = taui*(di2 - di3);
			ti3 = taui*(dr3 - dr2);
			ch[i - 1 + (3*k + 2)*ido] = tr2 + tr3;
			ch[ic - 1 + (3*k + 1)*ido] = tr2 - tr3;
			ch[i + (3*k + 2)*ido] = ti2 + ti3;
			ch[ic + (3*k + 1)*ido] = ti3 - ti2;
		}
    }
} /* radf3 */


static void radb3(Tint ido, Tint l1, const Treal cc[], Treal ch[], 
				  const Treal wa1[], const Treal wa2[])
{
    static const Treal taur = -0.5;
    static const Treal taui = 0.866025403784439;
    Tint i, k, ic;
    Treal ci2, ci3, di2, di3, cr2, cr3, dr2, dr3, ti2, tr2;
    for (k=0; k<l1; k++) {
		tr2 = 2*ref(cc,ido-1 + (3*k + 1)*ido);
		cr2 = ref(cc,3*k*ido) + taur*tr2;
		ch[k*ido] = ref(cc,3*k*ido) + tr2;
		ci3 = 2*taui*ref(cc,(3*k + 2)*ido);
		ch[(k + l1)*ido] = cr2 - ci3;
		ch[(k + 2*l1)*ido] = cr2 + ci3;
    }
    if (ido == 1) return;
    for (k=0; k<l1; k++) {
		for (i=2; i<ido; i+=2) {
			ic = ido - i;
			tr2 = ref(cc,i - 1 + (3*k + 2)*ido) + ref(cc,ic - 1 + (3*k + 1)*ido);
			cr2 = ref(cc,i - 1 + 3*k*ido) + taur*tr2;
			ch[i - 1 + k*ido] = ref(cc,i - 1 + 3*k*ido) + tr2;
			ti2 = ref(cc,i + (3*k + 2)*ido) - ref(cc,ic + (3*k + 1)*ido);
			ci2 = ref(cc,i + 3*k*ido) + taur*ti2;
			ch[i + k*ido] = ref(cc,i + 3*k*ido) + ti2;
			cr3 = taui*(ref(cc,i - 1 + (3*k + 2)*ido) - ref(cc,ic - 1 + (3*k + 1)*ido));
			ci3 = taui*(ref(cc,i + (3*k + 2)*ido) + ref(cc,ic + (3*k + 1)*ido));
			dr2 = cr2 - ci3;
			dr3 = cr2 + ci3;
			di2 = ci2 + cr3;
			di3 = ci2 - cr3;
			ch[i - 1 + (k + l1)*ido] = wa1[i - 2]*dr2 - wa1[i - 1]*di2;
			ch[i + (k + l1)*ido] = wa1[i - 2]*di2 + wa1[i - 1]*dr2;
			ch[i - 1 + (k + 2*l1)*ido] = wa2[i - 2]*dr3 - wa2[i - 1]*di3;
			ch[i + (k + 2*l1)*ido] = wa2[i - 2]*di3 + wa2[i - 1]*dr3;
		}
    }
} /* radb3 */


static void radf4(Tint ido, Tint l1, const Treal cc[], Treal ch[], 
				  const Treal wa1[], const Treal wa2[], const Treal wa3[])
{
    static const Treal hsqt2 = 0.7071067811865475;
    Tint i, k, ic;
    Treal ci2, ci3, ci4, cr2, cr3, cr4, ti1, ti2, ti3, ti4, tr1, tr2, tr3, tr4;
    for (k=0; k<l1; k++) {
		tr1 = ref(cc,(k + l1)*ido) + ref(cc,(k + 3*l1)*ido);
		tr2 = ref(cc,k*ido) + ref(cc,(k + 2*l1)*ido);
		ch[4*k*ido] = tr1 + tr2;
		ch[ido-1 + (4*k + 3)*ido] = tr2 - tr1;
		ch[ido-1 + (4*k + 1)*ido] = ref(cc,k*ido) - ref(cc,(k + 2*l1)*ido);
		ch[(4*k + 2)*ido] = ref(cc,(k + 3*l1)*ido) - ref(cc,(k + l1)*ido);
    }
    if (ido < 2) return;
    if (ido != 2) {
		for (k=0; k<l1; k++) {
			for (i=2; i<ido; i += 2) {
				ic = ido - i;
				cr2 = wa1[i - 2]*ref(cc,i - 1 + (k + l1)*ido) + wa1[i - 1]*ref(cc,i + (k + l1)*ido);
				ci2 = wa1[i - 2]*ref(cc,i + (k + l1)*ido) - wa1[i - 1]*ref(cc,i - 1 + (k + l1)*ido);
				cr3 = wa2[i - 2]*ref(cc,i - 1 + (k + 2*l1)*ido) + wa2[i - 1]*ref(cc,i + (k + 2*l1)*ido);
				ci3 = wa2[i - 2]*ref(cc,i + (k + 2*l1)*ido) - wa2[i - 1]*ref(cc,i - 1 + (k + 2*l1)*ido);
				cr4 = wa3[i - 2]*ref(cc,i - 1 + (k + 3*l1)*ido) + wa3[i - 1]*ref(cc,i + (k + 3*l1)*ido);
				ci4 = wa3[i - 2]*ref(cc,i + (k + 3*l1)*ido) - wa3[i - 1]*ref(cc,i - 1 + (k + 3*l1)*ido);
				tr1 = cr2 + cr4;
				tr4 = cr4 - cr2;
				ti1 = ci2 + ci4;
				ti4 = ci2 - ci4;
				ti2 = ref(cc,i + k*ido) + ci3;
				ti3 = ref(cc,i + k*ido) - ci3;
				tr2 = ref(cc,i - 1 + k*ido) + cr3;
				tr3 = ref(cc,i - 1 + k*ido) - cr3;
				ch[i - 1 + 4*k*ido] = tr1 + tr2;
				ch[ic - 1 + (4*k + 3)*ido] = tr2 - tr1;
				ch[i + 4*k*ido] = ti1 + ti2;
				ch[ic + (4*k + 3)*ido] = ti1 - ti2;
				ch[i - 1 + (4*k + 2)*ido] = ti4 + tr3;
				ch[ic - 1 + (4*k + 1)*ido] = tr3 - ti4;
				ch[i + (4*k + 2)*ido] = tr4 + ti3;
				ch[ic + (4*k + 1)*ido] = tr4 - ti3;
			}
		}
		if (ido % 2 == 1) return;
	}
    for (k=0; k<l1; k++) {
		ti1 = -hsqt2*(ref(cc,ido-1 + (k + l1)*ido) + ref(cc,ido-1 + (k + 3*l1)*ido));
		tr1 = hsqt2*(ref(cc,ido-1 + (k + l1)*ido) - ref(cc,ido-1 + (k + 3*l1)*ido));
		ch[ido-1 + 4*k*ido] = tr1 + ref(cc,ido-1 + k*ido);
		ch[ido-1 + (4*k + 2)*ido] = ref(cc,ido-1 + k*ido) - tr1;
		ch[(4*k + 1)*ido] = ti1 - ref(cc,ido-1 + (k + 2*l1)*ido);
		ch[(4*k + 3)*ido] = ti1 + ref(cc,ido-1 + (k + 2*l1)*ido);
    }
} /* radf4 */


static void radb4(Tint ido, Tint l1, const Treal cc[], Treal ch[], 
				  const Treal wa1[], const Treal wa2[], const Treal wa3[])
{
    static const Treal sqrt2 = 1.414213562373095;
    Tint i, k, ic;
    Treal ci2, ci3, ci4, cr2, cr3, cr4, ti1, ti2, ti3, ti4, tr1, tr2, tr3, tr4;
    for (k = 0; k < l1; k++) {
		tr1 = ref(cc,4*k*ido) - ref(cc,ido-1 + (4*k + 3)*ido);
		tr2 = ref(cc,4*k*ido) + ref(cc,ido-1 + (4*k + 3)*ido);
		tr3 = ref(cc,ido-1 + (4*k + 1)*ido) + ref(cc,ido-1 + (4*k + 1)*ido);
		tr4 = ref(cc,(4*k + 2)*ido) + ref(cc,(4*k + 2)*ido);
		ch[k*ido] = tr2 + tr3;
		ch[(k + l1)*ido] = tr1 - tr4;
		ch[(k + 2*l1)*ido] = tr2 - tr3;
		ch[(k + 3*l1)*ido] = tr1 + tr4;
    }
    if (ido < 2) return;
    if (ido != 2) {
		for (k = 0; k < l1; ++k) {
			for (i = 2; i < ido; i += 2) {
				ic = ido - i;
				ti1 = ref(cc,i + 4*k*ido) + ref(cc,ic + (4*k + 3)*ido);
				ti2 = ref(cc,i + 4*k*ido) - ref(cc,ic + (4*k + 3)*ido);
				ti3 = ref(cc,i + (4*k + 2)*ido) - ref(cc,ic + (4*k + 1)*ido);
				tr4 = ref(cc,i + (4*k + 2)*ido) + ref(cc,ic + (4*k + 1)*ido);
				tr1 = ref(cc,i - 1 + 4*k*ido) - ref(cc,ic - 1 + (4*k + 3)*ido);
				tr2 = ref(cc,i - 1 + 4*k*ido) + ref(cc,ic - 1 + (4*k + 3)*ido);
				ti4 = ref(cc,i - 1 + (4*k + 2)*ido) - ref(cc,ic - 1 + (4*k + 1)*ido);
				tr3 = ref(cc,i - 1 + (4*k + 2)*ido) + ref(cc,ic - 1 + (4*k + 1)*ido);
				ch[i - 1 + k*ido] = tr2 + tr3;
				cr3 = tr2 - tr3;
				ch[i + k*ido] = ti2 + ti3;
				ci3 = ti2 - ti3;
				cr2 = tr1 - tr4;
				cr4 = tr1 + tr4;
				ci2 = ti1 + ti4;
				ci4 = ti1 - ti4;
				ch[i - 1 + (k + l1)*ido] = wa1[i - 2]*cr2 - wa1[i - 1]*ci2;
				ch[i + (k + l1)*ido] = wa1[i - 2]*ci2 + wa1[i - 1]*cr2;
				ch[i - 1 + (k + 2*l1)*ido] = wa2[i - 2]*cr3 - wa2[i - 1]*ci3;
				ch[i + (k + 2*l1)*ido] = wa2[i - 2]*ci3 + wa2[i - 1]*cr3;
				ch[i - 1 + (k + 3*l1)*ido] = wa3[i - 2]*cr4 - wa3[i - 1]*ci4;
				ch[i + (k + 3*l1)*ido] = wa3[i - 2]*ci4 + wa3[i - 1]*cr4;
			}
		}
		if (ido % 2 == 1) return;
	}
    for (k = 0; k < l1; k++) {
		ti1 = ref(cc,(4*k + 1)*ido) + ref(cc,(4*k + 3)*ido);
		ti2 = ref(cc,(4*k + 3)*ido) - ref(cc,(4*k + 1)*ido);
		tr1 = ref(cc,ido-1 + 4*k*ido) - ref(cc,ido-1 + (4*k + 2)*ido);
		tr2 = ref(cc,ido-1 + 4*k*ido) + ref(cc,ido-1 + (4*k + 2)*ido);
		ch[ido-1 + k*ido] = tr2 + tr2;
		ch[ido-1 + (k + l1)*ido] = sqrt2*(tr1 - ti1);
		ch[ido-1 + (k + 2*l1)*ido] = ti2 + ti2;
		ch[ido-1 + (k + 3*l1)*ido] = -sqrt2*(tr1 + ti1);
    }
} /* radb4 */


static void radf5(Tint ido, Tint l1, const Treal cc[], Treal ch[], 
				  const Treal wa1[], const Treal wa2[], const Treal wa3[], const Treal wa4[])
{
    static const Treal tr11 = 0.309016994374947;
    static const Treal ti11 = 0.951056516295154;
    static const Treal tr12 = -0.809016994374947;
    static const Treal ti12 = 0.587785252292473;
    Tint i, k, ic;
    Treal ci2, di2, ci4, ci5, di3, di4, di5, ci3, cr2, cr3, dr2, dr3, dr4, dr5,
	     cr5, cr4, ti2, ti3, ti5, ti4, tr2, tr3, tr4, tr5;
    for (k = 0; k < l1; k++) {
		cr2 = ref(cc,(k + 4*l1)*ido) + ref(cc,(k + l1)*ido);
		ci5 = ref(cc,(k + 4*l1)*ido) - ref(cc,(k + l1)*ido);
		cr3 = ref(cc,(k + 3*l1)*ido) + ref(cc,(k + 2*l1)*ido);
		ci4 = ref(cc,(k + 3*l1)*ido) - ref(cc,(k + 2*l1)*ido);
		ch[5*k*ido] = ref(cc,k*ido) + cr2 + cr3;
		ch[ido-1 + (5*k + 1)*ido] = ref(cc,k*ido) + tr11*cr2 + tr12*cr3;
		ch[(5*k + 2)*ido] = ti11*ci5 + ti12*ci4;
		ch[ido-1 + (5*k + 3)*ido] = ref(cc,k*ido) + tr12*cr2 + tr11*cr3;
		ch[(5*k + 4)*ido] = ti12*ci5 - ti11*ci4;
    }
    if (ido == 1) return;
    for (k = 0; k < l1; ++k) {
		for (i = 2; i < ido; i += 2) {
			ic = ido - i;
			dr2 = wa1[i - 2]*ref(cc,i - 1 + (k + l1)*ido) + wa1[i - 1]*ref(cc,i + (k + l1)*ido);
			di2 = wa1[i - 2]*ref(cc,i + (k + l1)*ido) - wa1[i - 1]*ref(cc,i - 1 + (k + l1)*ido);
			dr3 = wa2[i - 2]*ref(cc,i - 1 + (k + 2*l1)*ido) + wa2[i - 1]*ref(cc,i + (k + 2*l1)*ido);
			di3 = wa2[i - 2]*ref(cc,i + (k + 2*l1)*ido) - wa2[i - 1]*ref(cc,i - 1 + (k + 2*l1)*ido);
			dr4 = wa3[i - 2]*ref(cc,i - 1 + (k + 3*l1)*ido) + wa3[i - 1]*ref(cc,i + (k + 3*l1)*ido);
			di4 = wa3[i - 2]*ref(cc,i + (k + 3*l1)*ido) - wa3[i - 1]*ref(cc,i - 1 + (k + 3*l1)*ido);
			dr5 = wa4[i - 2]*ref(cc,i - 1 + (k + 4*l1)*ido) + wa4[i - 1]*ref(cc,i + (k + 4*l1)*ido);
			di5 = wa4[i - 2]*ref(cc,i + (k + 4*l1)*ido) - wa4[i - 1]*ref(cc,i - 1 + (k + 4*l1)*ido);
			cr2 = dr2 + dr5;
			ci5 = dr5 - dr2;
			cr5 = di2 - di5;
			ci2 = di2 + di5;
			cr3 = dr3 + dr4;
			ci4 = dr4 - dr3;
			cr4 = di3 - di4;
			ci3 = di3 + di4;
			ch[i - 1 + 5*k*ido] = ref(cc,i - 1 + k*ido) + cr2 + cr3;
			ch[i + 5*k*ido] = ref(cc,i + k*ido) + ci2 + ci3;
			tr2 = ref(cc,i - 1 + k*ido) + tr11*cr2 + tr12*cr3;
			ti2 = ref(cc,i + k*ido) + tr11*ci2 + tr12*ci3;
			tr3 = ref(cc,i - 1 + k*ido) + tr12*cr2 + tr11*cr3;
			ti3 = ref(cc,i + k*ido) + tr12*ci2 + tr11*ci3;
			tr5 = ti11*cr5 + ti12*cr4;
			ti5 = ti11*ci5 + ti12*ci4;
			tr4 = ti12*cr5 - ti11*cr4;
			ti4 = ti12*ci5 - ti11*ci4;
			ch[i - 1 + (5*k + 2)*ido] = tr2 + tr5;
			ch[ic - 1 + (5*k + 1)*ido] = tr2 - tr5;
			ch[i + (5*k + 2)*ido] = ti2 + ti5;
			ch[ic + (5*k + 1)*ido] = ti5 - ti2;
			ch[i - 1 + (5*k + 4)*ido] = tr3 + tr4;
			ch[ic - 1 + (5*k + 3)*ido] = tr3 - tr4;
			ch[i + (5*k + 4)*ido] = ti3 + ti4;
			ch[ic + (5*k + 3)*ido] = ti4 - ti3;
		}
    }
} /* radf5 */


static void radb5(Tint ido, Tint l1, const Treal cc[], Treal ch[], 
				  const Treal wa1[], const Treal wa2[], const Treal wa3[], const Treal wa4[])
{
    static const Treal tr11 = 0.309016994374947;
    static const Treal ti11 = 0.951056516295154;
    static const Treal tr12 = -0.809016994374947;
    static const Treal ti12 = 0.587785252292473;
    Tint i, k, ic;
    Treal ci2, ci3, ci4, ci5, di3, di4, di5, di2, cr2, cr3, cr5, cr4, ti2, ti3,
	     ti4, ti5, dr3, dr4, dr5, dr2, tr2, tr3, tr4, tr5;
    for (k = 0; k < l1; k++) {
		ti5 = 2*ref(cc,(5*k + 2)*ido);
		ti4 = 2*ref(cc,(5*k + 4)*ido);
		tr2 = 2*ref(cc,ido-1 + (5*k + 1)*ido);
		tr3 = 2*ref(cc,ido-1 + (5*k + 3)*ido);
		ch[k*ido] = ref(cc,5*k*ido) + tr2 + tr3;
		cr2 = ref(cc,5*k*ido) + tr11*tr2 + tr12*tr3;
		cr3 = ref(cc,5*k*ido) + tr12*tr2 + tr11*tr3;
		ci5 = ti11*ti5 + ti12*ti4;
		ci4 = ti12*ti5 - ti11*ti4;
		ch[(k + l1)*ido] = cr2 - ci5;
		ch[(k + 2*l1)*ido] = cr3 - ci4;
		ch[(k + 3*l1)*ido] = cr3 + ci4;
		ch[(k + 4*l1)*ido] = cr2 + ci5;
    }
    if (ido == 1) return;
    for (k = 0; k < l1; ++k) {
		for (i = 2; i < ido; i += 2) {
			ic = ido - i;
			ti5 = ref(cc,i + (5*k + 2)*ido) + ref(cc,ic + (5*k + 1)*ido);
			ti2 = ref(cc,i + (5*k + 2)*ido) - ref(cc,ic + (5*k + 1)*ido);
			ti4 = ref(cc,i + (5*k + 4)*ido) + ref(cc,ic + (5*k + 3)*ido);
			ti3 = ref(cc,i + (5*k + 4)*ido) - ref(cc,ic + (5*k + 3)*ido);
			tr5 = ref(cc,i - 1 + (5*k + 2)*ido) - ref(cc,ic - 1 + (5*k + 1)*ido);
			tr2 = ref(cc,i - 1 + (5*k + 2)*ido) + ref(cc,ic - 1 + (5*k + 1)*ido);
			tr4 = ref(cc,i - 1 + (5*k + 4)*ido) - ref(cc,ic - 1 + (5*k + 3)*ido);
			tr3 = ref(cc,i - 1 + (5*k + 4)*ido) + ref(cc,ic - 1 + (5*k + 3)*ido);
			ch[i - 1 + k*ido] = ref(cc,i - 1 + 5*k*ido) + tr2 + tr3;
			ch[i + k*ido] = ref(cc,i + 5*k*ido) + ti2 + ti3;
			cr2 = ref(cc,i - 1 + 5*k*ido) + tr11*tr2 + tr12*tr3;

			ci2 = ref(cc,i + 5*k*ido) + tr11*ti2 + tr12*ti3;
			cr3 = ref(cc,i - 1 + 5*k*ido) + tr12*tr2 + tr11*tr3;

			ci3 = ref(cc,i + 5*k*ido) + tr12*ti2 + tr11*ti3;
			cr5 = ti11*tr5 + ti12*tr4;
			ci5 = ti11*ti5 + ti12*ti4;
			cr4 = ti12*tr5 - ti11*tr4;
			ci4 = ti12*ti5 - ti11*ti4;
			dr3 = cr3 - ci4;
			dr4 = cr3 + ci4;
			di3 = ci3 + cr4;
			di4 = ci3 - cr4;
			dr5 = cr2 + ci5;
			dr2 = cr2 - ci5;
			di5 = ci2 - cr5;
			di2 = ci2 + cr5;
			ch[i - 1 + (k + l1)*ido] = wa1[i - 2]*dr2 - wa1[i - 1]*di2;
			ch[i + (k + l1)*ido] = wa1[i - 2]*di2 + wa1[i - 1]*dr2;
			ch[i - 1 + (k + 2*l1)*ido] = wa2[i - 2]*dr3 - wa2[i - 1]*di3;
			ch[i + (k + 2*l1)*ido] = wa2[i - 2]*di3 + wa2[i - 1]*dr3;
			ch[i - 1 + (k + 3*l1)*ido] = wa3[i - 2]*dr4 - wa3[i - 1]*di4;
			ch[i + (k + 3*l1)*ido] = wa3[i - 2]*di4 + wa3[i - 1]*dr4;
			ch[i - 1 + (k + 4*l1)*ido] = wa4[i - 2]*dr5 - wa4[i - 1]*di5;
			ch[i + (k + 4*l1)*ido] = wa4[i - 2]*di5 + wa4[i - 1]*dr5;
		}
    }
} /* radb5 */


static void radfg(Tint ido, Tint ip, Tint l1, Tint idl1,
				  Treal cc[], Treal ch[], const Treal wa[])
{
    static const Treal twopi = 6.28318530717959;
    Tint idij, ipph, i, j, k, l, j2, ic, jc, lc, ik, is, nbd;
    Treal dc2, ai1, ai2, ar1, ar2, ds2, dcp, arg, dsp, ar1h, ar2h;
    arg = twopi / ip;
    dcp = cos(arg);
    dsp = sin(arg);
    ipph = (ip + 1) / 2;
    nbd = (ido - 1) / 2;
    if (ido != 1) {
		for (ik=0; ik<idl1; ik++) ch[ik] = cc[ik];
		for (j=1; j<ip; j++)
			for (k=0; k<l1; k++)
				ch[(k + j*l1)*ido] = cc[(k + j*l1)*ido];
		if (nbd <= l1) {
			is = -ido;
			for (j=1; j<ip; j++) {
				is += ido;
				idij = is-1;
				for (i=2; i<ido; i+=2) {
					idij += 2;
					for (k=0; k<l1; k++) {
						ch[i - 1 + (k + j*l1)*ido] =
							wa[idij - 1]*cc[i - 1 + (k + j*l1)*ido] + wa[idij]*cc[i + (k + j*l1)*ido];
						ch[i + (k + j*l1)*ido] =
							wa[idij - 1]*cc[i + (k + j*l1)*ido] - wa[idij]*cc[i - 1 + (k + j*l1)*ido];
					}
				}
			}
		} else {
			is = -ido;
			for (j=1; j<ip; j++) {
				is += ido;
				for (k=0; k<l1; k++) {
					idij = is-1;
					for (i=2; i<ido; i+=2) {
						idij += 2;
						ch[i - 1 + (k + j*l1)*ido] =
							wa[idij - 1]*cc[i - 1 + (k + j*l1)*ido] + wa[idij]*cc[i + (k + j*l1)*ido];
						ch[i + (k + j*l1)*ido] =
							wa[idij - 1]*cc[i + (k + j*l1)*ido] - wa[idij]*cc[i - 1 + (k + j*l1)*ido];
					}
				}
			}
		}
		if (nbd >= l1) {
			for (j=1; j<ipph; j++) {
				jc = ip - j;
				for (k=0; k<l1; k++) {
					for (i=2; i<ido; i+=2) {
						cc[i - 1 + (k + j*l1)*ido] = ch[i - 1 + (k + j*l1)*ido] + ch[i - 1 + (k + jc*l1)*ido];
						cc[i - 1 + (k + jc*l1)*ido] = ch[i + (k + j*l1)*ido] - ch[i + (k + jc*l1)*ido];
						cc[i + (k + j*l1)*ido] = ch[i + (k + j*l1)*ido] + ch[i + (k + jc*l1)*ido];
						cc[i + (k + jc*l1)*ido] = ch[i - 1 + (k + jc*l1)*ido] - ch[i - 1 + (k + j*l1)*ido];
					}
				}
			}
		} else {
			for (j=1; j<ipph; j++) {
				jc = ip - j;
				for (i=2; i<ido; i+=2) {
					for (k=0; k<l1; k++) {
						cc[i - 1 + (k + j*l1)*ido] =
							ch[i - 1 + (k + j*l1)*ido] + ch[i - 1 + (k + jc*l1)*ido];
						cc[i - 1 + (k + jc*l1)*ido] = ch[i + (k + j*l1)*ido] - ch[i + (k + jc*l1)*ido];
						cc[i + (k + j*l1)*ido] = ch[i + (k + j*l1)*ido] + ch[i + (k + jc*l1)*ido];
						cc[i + (k + jc*l1)*ido] = ch[i - 1 + (k + jc*l1)*ido] - ch[i - 1 + (k + j*l1)*ido];
					}
				}
			}
		}
	} else {	/* now ido == 1 */
		for (ik=0; ik<idl1; ik++) cc[ik] = ch[ik];
	}
	for (j=1; j<ipph; j++) {
		jc = ip - j;
		for (k=0; k<l1; k++) {
			cc[(k + j*l1)*ido] = ch[(k + j*l1)*ido] + ch[(k + jc*l1)*ido];
			cc[(k + jc*l1)*ido] = ch[(k + jc*l1)*ido] - ch[(k + j*l1)*ido];
		}
    }

    ar1 = 1;
    ai1 = 0;
    for (l=1; l<ipph; l++) {
		lc = ip - l;
		ar1h = dcp*ar1 - dsp*ai1;
		ai1 = dcp*ai1 + dsp*ar1;
		ar1 = ar1h;
		for (ik=0; ik<idl1; ik++) {
			ch[ik + l*idl1] = cc[ik] + ar1*cc[ik + idl1];
			ch[ik + lc*idl1] = ai1*cc[ik + (ip-1)*idl1];
		}
		dc2 = ar1;
		ds2 = ai1;
		ar2 = ar1;
		ai2 = ai1;
		for (j=2; j<ipph; j++) {
			jc = ip - j;
			ar2h = dc2*ar2 - ds2*ai2;
			ai2 = dc2*ai2 + ds2*ar2;
			ar2 = ar2h;
			for (ik=0; ik<idl1; ik++) {
				ch[ik + l*idl1] += ar2*cc[ik + j*idl1];
				ch[ik + lc*idl1] += ai2*cc[ik + jc*idl1];
			}
		}
    }
    for (j=1; j<ipph; j++)
		for (ik=0; ik<idl1; ik++)
			ch[ik] += cc[ik + j*idl1];

	if (ido >= l1) {
		for (k=0; k<l1; k++) {
			for (i=0; i<ido; i++) {
				ref(cc,i + k*ip*ido) = ch[i + k*ido];
			}
		}
	} else {
		for (i=0; i<ido; i++) {
			for (k=0; k<l1; k++) {
				ref(cc,i + k*ip*ido) = ch[i + k*ido];
			}
		}
	}
    for (j=1; j<ipph; j++) {
		jc = ip - j;
		j2 = 2*j;
		for (k=0; k<l1; k++) {
			ref(cc,ido-1 + (j2 - 1 + k*ip)*ido) =
				ch[(k + j*l1)*ido];
			ref(cc,(j2 + k*ip)*ido) =
				ch[(k + jc*l1)*ido];
		}
    }
    if (ido == 1) return;
    if (nbd >= l1) {
		for (j=1; j<ipph; j++) {
			jc = ip - j;
			j2 = 2*j;
			for (k=0; k<l1; k++) {
				for (i=2; i<ido; i+=2) {
					ic = ido - i;
					ref(cc,i - 1 + (j2 + k*ip)*ido) = ch[i - 1 + (k + j*l1)*ido] + ch[i - 1 + (k + jc*l1)*ido];
					ref(cc,ic - 1 + (j2 - 1 + k*ip)*ido) = ch[i - 1 + (k + j*l1)*ido] - ch[i - 1 + (k + jc*l1)*ido];
					ref(cc,i + (j2 + k*ip)*ido) = ch[i + (k + j*l1)*ido] + ch[i + (k + jc*l1)*ido];
					ref(cc,ic + (j2 - 1 + k*ip)*ido) = ch[i + (k + jc*l1)*ido] - ch[i + (k + j*l1)*ido];
				}
			}
		}
	} else {
		for (j=1; j<ipph; j++) {
			jc = ip - j;
			j2 = 2*j;
			for (i=2; i<ido; i+=2) {
				ic = ido - i;
				for (k=0; k<l1; k++) {
					ref(cc,i - 1 + (j2 + k*ip)*ido) = ch[i - 1 + (k + j*l1)*ido] + ch[i - 1 + (k + jc*l1)*ido];
					ref(cc,ic - 1 + (j2 - 1 + k*ip)*ido) = ch[i - 1 + (k + j*l1)*ido] - ch[i - 1 + (k + jc*l1)*ido];
					ref(cc,i + (j2 + k*ip)*ido) = ch[i + (k + j*l1)*ido] + ch[i + (k + jc*l1)*ido];
					ref(cc,ic + (j2 - 1 + k*ip)*ido) = ch[i + (k + jc*l1)*ido] - ch[i + (k + j*l1)*ido];
				}
			}
		}
	}
} /* radfg */


static void radbg(Tint ido, Tint ip, Tint l1, Tint idl1,
				  Treal cc[], Treal ch[], const Treal wa[])
{
    static const Treal twopi = 6.28318530717959;
    Tint idij, ipph, i, j, k, l, j2, ic, jc, lc, ik, is;
    Treal dc2, ai1, ai2, ar1, ar2, ds2;
    Tint nbd;
    Treal dcp, arg, dsp, ar1h, ar2h;
    arg = twopi / ip;
    dcp = cos(arg);
    dsp = sin(arg);
    nbd = (ido - 1) / 2;
    ipph = (ip + 1) / 2;
    if (ido >= l1) {
		for (k=0; k<l1; k++) {
			for (i=0; i<ido; i++) {
				ch[i + k*ido] = ref(cc,i + k*ip*ido);
			}
		}
	} else {
		for (i=0; i<ido; i++) {
			for (k=0; k<l1; k++) {
				ch[i + k*ido] = ref(cc,i + k*ip*ido);
			}
		}
	}
    for (j=1; j<ipph; j++) {
		jc = ip - j;
		j2 = 2*j;
		for (k=0; k<l1; k++) {
			ch[(k + j*l1)*ido] = ref(cc,ido-1 + (j2 - 1 + k*ip)*ido) + ref(cc,ido-1 + (j2 - 1 + k*ip)*ido);
			ch[(k + jc*l1)*ido] = ref(cc,(j2 + k*ip)*ido) + ref(cc,(j2 + k*ip)*ido);
		}
    }

    if (ido != 1) {
		if (nbd >= l1) {
			for (j=1; j<ipph; j++) {
				jc = ip - j;
				for (k=0; k<l1; k++) {
					for (i=2; i<ido; i+=2) {
						ic = ido - i;
						ch[i - 1 + (k + j*l1)*ido] = ref(cc,i - 1 + (2*j + k*ip)*ido) + ref(cc,ic - 1 + (2*j - 1 + k*ip)*ido);
						ch[i - 1 + (k + jc*l1)*ido] = ref(cc,i - 1 + (2*j + k*ip)*ido) - ref(cc,ic - 1 + (2*j - 1 + k*ip)*ido);
						ch[i + (k + j*l1)*ido] = ref(cc,i + (2*j + k*ip)*ido) - ref(cc,ic + (2*j - 1 + k*ip)*ido);
						ch[i + (k + jc*l1)*ido] = ref(cc,i + (2*j + k*ip)*ido) + ref(cc,ic + (2*j - 1 + k*ip)*ido);
					}
				}
			}
		} else {
			for (j=1; j<ipph; j++) {
				jc = ip - j;
				for (i=2; i<ido; i+=2) {
					ic = ido - i;
					for (k=0; k<l1; k++) {
						ch[i - 1 + (k + j*l1)*ido] = ref(cc,i - 1 + (2*j + k*ip)*ido) + ref(cc,ic - 1 + (2*j - 1 + k*ip)*ido);
						ch[i - 1 + (k + jc*l1)*ido] = ref(cc,i - 1 + (2*j + k*ip)*ido) - ref(cc,ic - 1 + (2*j - 1 + k*ip)*ido);
						ch[i + (k + j*l1)*ido] = ref(cc,i + (2*j + k*ip)*ido) - ref(cc,ic + (2*j - 1 + k*ip)*ido);
						ch[i + (k + jc*l1)*ido] = ref(cc,i + (2*j + k*ip)*ido) + ref(cc,ic + (2*j - 1 + k*ip)*ido);
					}
				}
			}
		}
	}

	ar1 = 1;
    ai1 = 0;
    for (l=1; l<ipph; l++) {
		lc = ip - l;
		ar1h = dcp*ar1 - dsp*ai1;
		ai1 = dcp*ai1 + dsp*ar1;
		ar1 = ar1h;
		for (ik=0; ik<idl1; ik++) {
			cc[ik + l*idl1] = ch[ik] + ar1*ch[ik + idl1];
			cc[ik + lc*idl1] = ai1*ch[ik + (ip-1)*idl1];
		}
		dc2 = ar1;
		ds2 = ai1;
		ar2 = ar1;
		ai2 = ai1;
		for (j=2; j<ipph; j++) {
			jc = ip - j;
			ar2h = dc2*ar2 - ds2*ai2;
			ai2 = dc2*ai2 + ds2*ar2;
			ar2 = ar2h;
			for (ik=0; ik<idl1; ik++) {
				cc[ik + l*idl1] += ar2*ch[ik + j*idl1];
				cc[ik + lc*idl1] += ai2*ch[ik + jc*idl1];
			}
		}
    }
    for (j=1; j<ipph; j++) {
		for (ik=0; ik<idl1; ik++) {
			ch[ik] += ch[ik + j*idl1];
		}
    }
    for (j=1; j<ipph; j++) {
		jc = ip - j;
		for (k=0; k<l1; k++) {
			ch[(k + j*l1)*ido] = cc[(k + j*l1)*ido] - cc[(k + jc*l1)*ido];
			ch[(k + jc*l1)*ido] = cc[(k + j*l1)*ido] + cc[(k + jc*l1)*ido];
		}
    }
	
    if (ido == 1) return;
	if (nbd >= l1) {
		for (j=1; j<ipph; j++) {
			jc = ip - j;
			for (k=0; k<l1; k++) {
				for (i=2; i<ido; i+=2) {
					ch[i - 1 + (k + j*l1)*ido] = cc[i - 1 + (k + j*l1)*ido] - cc[i + (k + jc*l1)*ido];
					ch[i - 1 + (k + jc*l1)*ido] = cc[i - 1 + (k + j*l1)*ido] + cc[i + (k + jc*l1)*ido];
					ch[i + (k + j*l1)*ido] = cc[i + (k + j*l1)*ido] + cc[i - 1 + (k + jc*l1)*ido];
					ch[i + (k + jc*l1)*ido] = cc[i + (k + j*l1)*ido] - cc[i - 1 + (k + jc*l1)*ido];
				}
			}
		}
	} else {
		for (j=1; j<ipph; j++) {
			jc = ip - j;
			for (i=2; i<ido; i+=2) {
				for (k=0; k<l1; k++) {
					ch[i - 1 + (k + j*l1)*ido] = cc[i - 1 + (k + j*l1)*ido] - cc[i + (k + jc*l1)*ido];
					ch[i - 1 + (k + jc*l1)*ido] = cc[i - 1 + (k + j *l1)*ido] + cc[i + (k + jc*l1)*ido];
					ch[i + (k + j*l1)*ido] = cc[i + (k + j*l1)*ido] + cc[i - 1 + (k + jc*l1)*ido];
					ch[i + (k + jc*l1)*ido] = cc[i + (k + j*l1)*ido] - cc[i - 1 + (k + jc*l1)*ido];
				}
			}
		}
	}
    for (ik=0; ik<idl1; ik++) cc[ik] = ch[ik];
    for (j=1; j<ip; j++)
		for (k=0; k<l1; k++)
			cc[(k + j*l1)*ido] = ch[(k + j*l1)*ido];
    if (nbd <= l1) {
		is = -ido;
		for (j=1; j<ip; j++) {
			is += ido;
			idij = is-1;
			for (i=2; i<ido; i+=2) {
				idij += 2;
				for (k=0; k<l1; k++) {
					cc[i - 1 + (k + j*l1)*ido] = wa[idij - 1]*ch[i - 1 + (k + j*l1)*ido] - wa[idij]*ch[i + (k + j*l1)*ido];
					cc[i + (k + j*l1)*ido] = wa[idij - 1]*ch[i + (k + j*l1)*ido] + wa[idij]*ch[i - 1 + (k + j*l1)*ido];
				}
			}
		}
	} else {
		is = -ido;
		for (j=1; j<ip; j++) {
			is += ido;
			for (k=0; k<l1; k++) {
				idij = is;
				for (i=2; i<ido; i+=2) {
					idij += 2;
					cc[i - 1 + (k + j*l1)*ido] = wa[idij-1]*ch[i - 1 + (k + j*l1)*ido] - wa[idij]*ch[i + (k + j*l1)*ido];
					cc[i + (k + j*l1)*ido] = wa[idij-1]*ch[i + (k + j*l1)*ido] + wa[idij]*ch[i - 1 + (k + j*l1)*ido];
				}
			}
		}
	}
} /* radbg */

/* ----------------------------------------------------------------------
   cfftf1, cfftf, cfftb, cffti1, cffti. Complex FFTs.
   ---------------------------------------------------------------------- */

static void cfftf1(Tint n, Treal c[], Treal ch[], const Treal wa[], const Tint ifac[MAXFAC+2], int isign)
{
    Tint idot, i;
    Tint k1, l1, l2;
    Tint na, nf, ip, iw, ix2, ix3, ix4, nac, ido, idl1;
	Treal *cinput, *coutput;
    nf = ifac[1];
    na = 0;
    l1 = 1;
    iw = 0;
    for (k1=2; k1<=nf+1; k1++) {
		ip = ifac[k1];
		l2 = ip*l1;
		ido = n / l2;
		idot = ido + ido;
		idl1 = idot*l1;
		if (na) {
			cinput = ch;
			coutput = c;
		} else {
			cinput = c;
			coutput = ch;
		}
		switch (ip) {
		 case 4:
			ix2 = iw + idot;
			ix3 = ix2 + idot;
			passf4(idot, l1, cinput, coutput, &wa[iw], &wa[ix2], &wa[ix3], isign);
			na = !na;
			break;
		 case 2:
			passf2(idot, l1, cinput, coutput, &wa[iw], isign);
			na = !na;
			break;
		 case 3:
			ix2 = iw + idot;
			passf3(idot, l1, cinput, coutput, &wa[iw], &wa[ix2], isign);
			na = !na;
			break;
		 case 5:
			ix2 = iw + idot;
			ix3 = ix2 + idot;
			ix4 = ix3 + idot;
			passf5(idot, l1, cinput, coutput, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4], isign);
			na = !na;
			break;
		 default:
			passf(&nac, idot, ip, l1, idl1, cinput, coutput, &wa[iw], isign);
			if (nac != 0) na = !na;
		}
		l1 = l2;
		iw += (ip - 1)*idot;
    }
    if (na == 0) return;
    for (i=0; i<2*n; i++) c[i] = ch[i];
} /* cfftf1 */


void cfftf(Tint n, Treal c[], Treal wsave[])
{
    Tint iw1, iw2;
    if (n == 1) return;
    iw1 = 2*n;
    iw2 = iw1 + 2*n;
    cfftf1(n, c, wsave, wsave+iw1, (Tint*)(wsave+iw2), -1);
} /* cfftf */


void cfftb(Tint n, Treal c[], Treal wsave[])
{
    Tint iw1, iw2;
    if (n == 1) return;
    iw1 = 2*n;
    iw2 = iw1 + 2*n;
    cfftf1(n, c, wsave, wsave+iw1, (Tint*)(wsave+iw2), +1);
} /* cfftb */


static void factorize(Tint n, Tint ifac[MAXFAC+2])
/* Factorize n in factors of 2,3,4,5 and rest. On exit,
   ifac[0] contains n and ifac[1] contains number of factors,
   the factors start from ifac[2]. */
{
    static const Tint ntryh[4] = {3,4,2,5};
    Tint ntry=3, i, j=0, ib, nf=0, nl=n, nq, nr;
 startloop:
	if (j < 4)
		ntry = ntryh[j];
	else
		ntry+= 2;
	j++;
	do {
		nq = nl / ntry;
		nr = nl - ntry*nq;
		if (nr != 0) goto startloop;
		nf++;
		ifac[nf + 1] = ntry;
		nl = nq;
		if (ntry == 2 && nf != 1) {
			for (i=2; i<=nf; i++) {
				ib = nf - i + 2;
				ifac[ib + 1] = ifac[ib];
			}
			ifac[2] = 2;
		}
	} while (nl != 1);
    ifac[0] = n;
    ifac[1] = nf;
}


static void cffti1(Tint n, Treal wa[], Tint ifac[MAXFAC+2])
{
    static const Treal twopi = 6.28318530717959;
    Treal arg, argh, argld, fi;
    Tint idot, i, j;
    Tint i1, k1, l1, l2;
    Tint ld, ii, nf, ip;
    Tint ido, ipm;

	factorize(n,ifac);
	nf = ifac[1];
    argh = twopi/(Treal)n;
    i = 1;
    l1 = 1;
    for (k1=1; k1<=nf; k1++) {
		ip = ifac[k1+1];
		ld = 0;
		l2 = l1*ip;
		ido = n / l2;
		idot = ido + ido + 2;
		ipm = ip - 1;
		for (j=1; j<=ipm; j++) {
			i1 = i;
			wa[i-1] = 1;
			wa[i] = 0;
			ld += l1;
			fi = 0;
			argld = ld*argh;
			for (ii=4; ii<=idot; ii+=2) {
				i+= 2;
				fi+= 1;
				arg = fi*argld;
				wa[i-1] = cos(arg);
				wa[i] = sin(arg);
			}
			if (ip > 5) {
				wa[i1-1] = wa[i-1];
				wa[i1] = wa[i];
			}
		}
		l1 = l2;
    }
} /* cffti1 */


void cffti(Tint n, Treal wsave[])
{
    Tint iw1, iw2;
    if (n == 1) return;
    iw1 = 2*n;
    iw2 = iw1 + 2*n;
    cffti1(n, wsave+iw1, (Tint*)(wsave+iw2));
} /* cffti */

/* ----------------------------------------------------------------------
   rfftf1, rfftb1, rfftf, rfftb, rffti1, rffti. Real FFTs.
   ---------------------------------------------------------------------- */

static void rfftf1(Tint n, Treal c[], Treal ch[], const Treal wa[], const Tint ifac[MAXFAC+2])
{
    Tint i;
    Tint k1, l1, l2, na, kh, nf, ip, iw, ix2, ix3, ix4, ido, idl1;
	Treal *cinput, *coutput;
    nf = ifac[1];
    na = 1;
    l2 = n;
    iw = n-1;
    for (k1 = 1; k1 <= nf; ++k1) {
		kh = nf - k1;
		ip = ifac[kh + 2];
		l1 = l2 / ip;
		ido = n / l2;
		idl1 = ido*l1;
		iw -= (ip - 1)*ido;
		na = !na;
		if (na) {
			cinput = ch;
			coutput = c;
		} else {
			cinput = c;
			coutput = ch;
		}
		switch (ip) {
		 case 4:
			ix2 = iw + ido;
			ix3 = ix2 + ido;
			radf4(ido, l1, cinput, coutput, &wa[iw], &wa[ix2], &wa[ix3]);
			break;
		 case 2:
			radf2(ido, l1, cinput, coutput, &wa[iw]);
			break;
		 case 3:
			ix2 = iw + ido;
			radf3(ido, l1, cinput, coutput, &wa[iw], &wa[ix2]);
			break;
		 case 5:
			ix2 = iw + ido;
			ix3 = ix2 + ido;
			ix4 = ix3 + ido;
			radf5(ido, l1, cinput, coutput, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4]);
			break;
		 default:
			if (ido == 1)
				na = !na;
			if (na == 0) {
				radfg(ido, ip, l1, idl1, c, ch, &wa[iw]);
				na = 1;
			} else {
				radfg(ido, ip, l1, idl1, ch, c, &wa[iw]);
				na = 0;
			}
		}
		l2 = l1;
    }
    if (na == 1) return;
    for (i = 0; i < n; i++) c[i] = ch[i];
} /* rfftf1 */


void rfftb1(Tint n, Treal c[], Treal ch[], const Treal wa[], const Tint ifac[MAXFAC+2])
{
    Tint i;
    Tint k1, l1, l2, na, nf, ip, iw, ix2, ix3, ix4, ido, idl1;
	Treal *cinput, *coutput;
    nf = ifac[1];
    na = 0;
    l1 = 1;
    iw = 0;
    for (k1=1; k1<=nf; k1++) {
		ip = ifac[k1 + 1];
		l2 = ip*l1;
		ido = n / l2;
		idl1 = ido*l1;
		if (na) {
			cinput = ch;
			coutput = c;
		} else {
			cinput = c;
			coutput = ch;
		}
		switch (ip) {
		 case 4:
			ix2 = iw + ido;
			ix3 = ix2 + ido;
			radb4(ido, l1, cinput, coutput, &wa[iw], &wa[ix2], &wa[ix3]);
			na = !na;
			break;
		 case 2:
			radb2(ido, l1, cinput, coutput, &wa[iw]);
			na = !na;
			break;
		 case 3:
			ix2 = iw + ido;
			radb3(ido, l1, cinput, coutput, &wa[iw], &wa[ix2]);
			na = !na;
			break;
		 case 5:
			ix2 = iw + ido;
			ix3 = ix2 + ido;
			ix4 = ix3 + ido;
			radb5(ido, l1, cinput, coutput, &wa[iw], &wa[ix2], &wa[ix3], &wa[ix4]);
			na = !na;
			break;
		 default:
			radbg(ido, ip, l1, idl1, cinput, coutput, &wa[iw]);
			if (ido == 1) na = !na;
		}
		l1 = l2;
		iw += (ip - 1)*ido;
    }
    if (na == 0) return;
    for (i=0; i<n; i++) c[i] = ch[i];
} /* rfftb1 */


void rfftf(Tint n, Treal r[], Treal wsave[])
{
    if (n == 1) return;
    rfftf1(n, r, wsave, wsave+n, (Tint*)(wsave+2*n));
} /* rfftf */


void rfftb(Tint n, Treal r[], Treal wsave[])
{
    if (n == 1) return;
    rfftb1(n, r, wsave, wsave+n, (Tint*)(wsave+2*n));
} /* rfftb */


static void rffti1(Tint n, Treal wa[], Tint ifac[MAXFAC+2])
{
    static const Treal twopi = 6.28318530717959;
    Treal arg, argh, argld, fi;
    Tint i, j;
    Tint k1, l1, l2;
    Tint ld, ii, nf, ip, is;
    Tint ido, ipm, nfm1;
	factorize(n,ifac);
	nf = ifac[1];
    argh = twopi / n;
    is = 0;
    nfm1 = nf - 1;
    l1 = 1;
    if (nfm1 == 0) return;
    for (k1 = 1; k1 <= nfm1; k1++) {
		ip = ifac[k1 + 1];
		ld = 0;
		l2 = l1*ip;
		ido = n / l2;
		ipm = ip - 1;
		for (j = 1; j <= ipm; ++j) {
			ld += l1;
			i = is;
			argld = (Treal) ld*argh;
			fi = 0;
			for (ii = 3; ii <= ido; ii += 2) {
				i += 2;
				fi += 1;
				arg = fi*argld;
				wa[i - 2] = cos(arg);
				wa[i - 1] = sin(arg);
			}
			is += ido;
		}
		l1 = l2;
    }
} /* rffti1 */


void rffti(Tint n, Treal wsave[])
{
    if (n == 1) return;
    rffti1(n, wsave+n, (Tint*)(wsave+2*n));
} /* rffti */

/* ----------------------------------------------------------------------
   cosqf1, cosqb1, cosqf, cosqb, cosqi. Quarter-wave cos-FFTs.
   ---------------------------------------------------------------------- */

static void cosqf1(Tint n, Treal x[], Treal w[], Treal xh[])
{
    Tint modn, i, k;
    Tint kc, np2, ns2;
    Treal xim1;
    ns2 = (n + 1) / 2;
    np2 = n + 2;
    for (k=1; k<ns2; k++) {
		kc = n - k;
		xh[k] = x[k] + x[kc];
		xh[kc] = x[k] - x[kc];
    }
    modn = n % 2;
    if (modn == 0)
		xh[ns2] = x[ns2] + x[ns2];
    for (k=1; k<ns2; k++) {
		kc = n - k;
		x[k] = w[k - 1]*xh[kc] + w[kc - 1]*xh[k];
		x[kc] = w[k - 1]*xh[k] - w[kc - 1]*xh[kc];
    }
    if (modn == 0)
		x[ns2] = w[ns2-1]*xh[ns2];
    rfftf(n, x, xh);
    for (i=2; i<n; i+=2) {
		xim1 = x[i - 1] - x[i];
		x[i] = x[i - 1] + x[i];
		x[i - 1] = xim1;
    }
} /* cosqf1 */


static void cosqb1(Tint n, Treal x[], Treal w[], Treal xh[])
{
    Tint modn, i, k;
    Tint kc, ns2;
    Treal xim1;
    ns2 = (n + 1) / 2;
    for (i=2; i<n; i+=2) {
		xim1 = x[i - 1] + x[i];
		x[i] -= x[i - 1];
		x[i - 1] = xim1;
    }
    x[0] += x[0];
    modn = n % 2;
    if (modn == 0)
		x[n-1] += x[n-1];
    rfftb(n, x, xh);
    for (k=1; k<ns2; k++) {
		kc = n - k;
		xh[k] = w[k - 1]*x[kc] + w[kc - 1]*x[k];
		xh[kc] = w[k - 1]*x[k] - w[kc - 1]*x[kc];
    }
    if (modn == 0)
		x[ns2] = w[ns2-1]*(x[ns2] + x[ns2]);
    for (k=1; k<ns2; k++) {
		kc = n - k;
		x[k] = xh[k] + xh[kc];
		x[kc] = xh[k] - xh[kc];
    }
    x[0] += x[0];
} /* cosqb1 */


void cosqf(Tint n, Treal x[], Treal wsave[])
{
    static const Treal sqrt2 = 1.4142135623731;
    Treal tsqx;
    if (n < 2) {
		return;
    } else if (n == 2) {
		tsqx = sqrt2*x[1];
		x[1] = x[0] - tsqx;
		x[0] += tsqx;
    } else {
		cosqf1(n, x, wsave, &wsave[n]);
    }
} /* cosqf */


void cosqb(Tint n, Treal x[], Treal wsave[])
{
    static const Treal tsqrt2 = 2.82842712474619;
    Treal x1;
    if (n < 2) {
		x[0] *= 4;
    } else if (n == 2) {
		x1 = 4*(x[0] + x[1]);
		x[1] = tsqrt2*(x[0] - x[1]);
		x[0] = x1;
    } else
		cosqb1(n, x, wsave, &wsave[n]);
} /* cosqb */


void cosqi(Tint n, Treal wsave[])
{
    static const Treal pih = 1.57079632679491;
    Tint k;
    Treal dt;
    dt = pih/n;
    for (k=0; k<n; k++)
		wsave[k] = cos((k+1)*dt);
    rffti(n, &wsave[n]);
} /* cosqi */

/* ----------------------------------------------------------------------
   cost, costi. Full-wave cos-FFTs.
   ---------------------------------------------------------------------- */

void cost(Tint n, Treal x[], Treal wsave[])
{
    Tint modn, i, k;
    Treal c1, t1, t2;
    Tint kc;
    Treal xi;
    Tint nm1;
    Treal x1h;
    Tint ns2;
    Treal tx2, x1p3, xim2;
    nm1 = n - 1;
    ns2 = n / 2;
    if (n - 2 < 0)
		return;
    else if (n == 2) {
		x1h = x[0] + x[1];
		x[1] = x[0] - x[1];
		x[0] = x1h;
    } else if (n == 3) {
		x1p3 = x[0] + x[2];
		tx2 = x[1] + x[1];
		x[1] = x[0] - x[2];
		x[0] = x1p3 + tx2;
		x[2] = x1p3 - tx2;
	} else {
		c1 = x[0] - x[n-1];
		x[0] += x[n-1];
		for (k=1; k<ns2; k++) {
			kc = nm1 - k;
			t1 = x[k] + x[kc];
			t2 = x[k] - x[kc];
			c1 += wsave[kc]*t2;
			t2 = wsave[k]*t2;
			x[k] = t1 - t2;
			x[kc] = t1 + t2;
		}
		modn = n % 2;
		if (modn != 0)
			x[ns2] += x[ns2];
		rfftf(nm1, x, &wsave[n]);
		xim2 = x[1];
		x[1] = c1;
		for (i=3; i<n; i+=2) {
			xi = x[i];
			x[i] = x[i - 2] - x[i - 1];
			x[i - 1] = xim2;
			xim2 = xi;
		}
		if (modn != 0) x[n-1] = xim2;
	}
} /* cost */


void costi(Tint n, Treal wsave[])
{
    static const Treal pi = 3.14159265358979;
    Tint k,kc,ns2;
    Treal dt;
    if (n <= 3) return;
    ns2 = n / 2;
    dt = pi / (n-1);
    for (k = 1; k < ns2; k++) {
		kc = n - k - 1;
		wsave[k] = 2*sin(k*dt);
		wsave[kc] = 2*cos(k*dt);
    }
    rffti(n-1, &wsave[n]);
} /* costi */

/* ----------------------------------------------------------------------
   sinqf, sinqb, sinqi. Quarter-wave sin-FFTs. These call cosqf etc.
   ---------------------------------------------------------------------- */

void sinqf(Tint n, Treal x[], Treal wsave[])
{
    Tint k;
    Treal xhold;
    Tint kc, ns2;
    if (n == 1) return;
    ns2 = n / 2;
    for (k=0; k<ns2; k++) {
		kc = n - k - 1;
		xhold = x[k];
		x[k] = x[kc];
		x[kc] = xhold;
    }
    cosqf(n, x, wsave);
    for (k=1; k<n; k+=2)
		x[k] = -x[k];
} /* sinqf */


void sinqb(Tint n, Treal x[], Treal wsave[])
{
    Tint k;
    Treal xhold;
    Tint kc, ns2;
    if (n <= 1) {
		x[0] *= 4;
		return;
	}
    ns2 = n / 2;
    for (k=1; k<n; k+=2) x[k] = -x[k];
    cosqb(n, x, wsave);
    for (k=0; k<ns2; k++) {
		kc = n - k - 1;
		xhold = x[k];
		x[k] = x[kc];
		x[kc] = xhold;
    }
} /* sinqb */


void sinqi(Tint n, Treal wsave[])
{
    cosqi(n, wsave);
}

/* ----------------------------------------------------------------------
   sint1, sint, sinti. Full-wave sin-FFTs.
   ---------------------------------------------------------------------- */

static void sint1(Tint n, Treal war[], const Treal was[], Treal xh[], Treal x[], const Tint ifac[MAXFAC+2])
{
    static const Treal sqrt3 = 1.73205080756888;
    Tint modn, i, k;
    Treal xhold, t1, t2;
    Tint kc, np1, ns2;

    for (i=0; i<n; i++) {
		xh[i] = war[i];
		war[i] = x[i];
    }
    if (n < 2) {
		xh[0] += xh[0];
    } else if (n == 2) {
		xhold = sqrt3*(xh[0] + xh[1]);
		xh[1] = sqrt3*(xh[0] - xh[1]);
		xh[0] = xhold;
    } else {
		np1 = n + 1;
		ns2 = n / 2;
		x[0] = 0;
		for (k=0; k<ns2; k++) {
			kc = n - k - 1;
			t1 = xh[k] - xh[kc];
			t2 = was[k]*(xh[k] + xh[kc]);
			x[k + 1] = t1 + t2;
			x[kc + 1] = t2 - t1;
		}
		modn = n % 2;
		if (modn != 0)
			x[ns2 + 1] = 4*xh[ns2];
		rfftf1(np1, x, xh, war, ifac);
		xh[0] = 0.5*x[0];
		for (i=2; i<n; i+=2) {
			xh[i-1] = -x[i];
			xh[i] = xh[i-2] + x[i-1];
		}
		if (modn == 0) xh[n-1] = -x[n];
	}
    for (i=0; i<n; i++) {
		x[i] = war[i];
		war[i] = xh[i];
    }
} /* sint1 */


void sint(Tint n, Treal x[], Treal wsave[])
{
    Tint iw1, iw2, iw3;
    iw1 = n / 2;
    iw2 = iw1 + n + 1;
    iw3 = iw2 + n + 1;
    sint1(n, x, wsave, wsave+iw1, wsave+iw2, (Tint*)(wsave+iw3));
} /* sint */


void sinti(Tint n, Treal wsave[])
{
    static const Treal pi = 3.14159265358979;
    Tint k,ns2;
    Treal dt;
    if (n <= 1) return;
    ns2 = n / 2;
    dt = pi / (n+1);
    for (k=0; k<ns2; k++)
		wsave[k] = 2*sin((k+1)*dt);
    rffti(n+1, &wsave[ns2]);
} /* sinti */

#ifdef __cplusplus
}
#endif
