/*
 *
 * fft.c written by S. ISHIZAKA 1999/07
 * 
 */

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

#define PI 3.141592653589793

#define MAXP 12
#define MAXDATA 4096

double fr[MAXDATA],fi[MAXDATA],gr[MAXDATA],gi[MAXDATA];
double workr[MAXDATA/2],worki[MAXDATA/2];

void fft(int p,int num);

int main(int argc,char **argv)
{
  char *fname1,*fname2;
  FILE *fp1,*fp2;
  int n,p,num,i;
  double x,y,minx,maxx,dx;

  if (argc<3) {
    fprintf(stderr,"usage: fft input output");
    exit(1);
  }
  fname1=argv[1];
  fname2=argv[2];
  if ((fp1=fopen(fname1,"rt"))==NULL) {
    fprintf(stderr,"error: open (%s)",fname1);
    exit(1);
  }
  if ((fp2=fopen(fname2,"wt"))==NULL) {
    fprintf(stderr,"error: open (%s)",fname2);
    exit(1);
  }
  num=0;
  n=1;
  p=0;
  while (fscanf(fp1,"%lf%lf",&x,&y)==2) {
    if (num==0) minx=x;
    fr[num]=y;
    fi[num]=0;
    num++;
    if (num==(n*2)) {
      n*=2;
      p++;
      if (p==MAXP) break;
      maxx=x;
    }
  }
  if (num<2) {
    fprintf(stderr,"error: too small number of data");
    exit(1);
  }
  fft(p,n);
  dx=(n-1)/(maxx-minx)/n;
  for (i=n/2;i<n;i++)
    fprintf(fp2,"%f %f %f\n",dx*(i-n),gr[i],gi[i]);
  for (i=0;i<n/2;i++)
    fprintf(fp2,"%f %f %f\n",dx*i,gr[i],gi[i]);
  fclose(fp1);
  fclose(fp2);
  return 0;
}

void fft(int p,int n)
{
  int i,j,k,l,l1,l2,m,n2;
  double ar,ai,br,bi;

  n2=n/2;
  for (i=0;i<n2;i++) {
    workr[i]=cos(2*PI/n*i);
    worki[i]=sin(2*PI/n*i);
  }
  for (j=0;j<n2;j++) {
    k=j*2;
    gr[k]=fr[j]+fr[j+n2];
    gi[k]=fi[j]+fi[j+n2];
    gr[k+1]=fr[j]-fr[j+n2];
    gi[k+1]=fi[j]-fi[j+n2];
  }
  l1=1;
  for (l=1;l<p;l++) {
    l1*=2;
    l2=n2/l1;
    for (i=0;i<n;i++) {
      fr[i]=gr[i];
      fi[i]=gi[i];
    }
    for (k=0;k<l1;k++) {
      for (j=0;j<l2;j++) {
        m=j*l1;
        ar=fr[m+k];
        ai=fi[m+k];
        br=fr[m+k+n2]*workr[k*l2]-fi[m+k+n2]*worki[k*l2];
        bi=fr[m+k+n2]*worki[k*l2]+fi[m+k+n2]*workr[k*l2];
        gr[m+m+k]=ar+br;
        gi[m+m+k]=ai+bi;
        gr[m+m+k+l1]=ar-br;
        gi[m+m+k+l1]=ai-bi;
      }
    }
  }
  for (i=0;i<n;i++) {
    gr[i]/=n;
    gi[i]/=n;
  }
}
