/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	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.

**********************************************************************/


#include	<stdlib.h>
#include	<stdio.h>
#include	"u_math.h"
#include	"complex.h"

COMPLEX * w_list;
int w_list_size;
int w_list_sign;

void
new_w_list(int size,int sign)
{
int i;
	if ( w_list_size == size && w_list_sign == sign )
		return;
	if ( w_list )
		free(w_list);
	w_list = malloc(sizeof(COMPLEX)*size);
	w_list_size = size;
	w_list_sign = sign;
	for ( i = 0 ; i < size ; i ++ ) {
		w_list[i].re = cos(2*M_PI*i/size);
		w_list[i].im = sign*sin(2*M_PI*i/size);
	}
}

int upsidedown(int a,int b)
{
int i;
int ret;
	ret = 0;
	for ( i = 0 ; i < b ; i ++ ) {
		ret <<= 1;
		if ( a & 1 )
			ret |= 1;
		a >>= 1;
	}
	return ret;
}

void
print_all(COMPLEX * a,int b)
{
int i;
	printf("a\n");
	for ( i = 0 ; i < b ; i ++ ) {
		printf("\t%i (%lf, %lf)\n",
			i,a[i].re,a[i].im);
	}
}

COMPLEX * 
_fastft(COMPLEX * list,int beki,int sign)
{
COMPLEX * ret;
int i,imax,j,k,l,kstep;
int size;
COMPLEX a,b,c;
	size = 1<<beki;
	new_w_list(size,sign);
	ret = malloc(sizeof(COMPLEX)*size);
	for ( i = 0 ; i < size ; i ++ )
		ret[upsidedown(i,beki)] = list[i];
	imax = 1<<(beki-1);
	kstep = imax;
	for ( i = 1 ; i < size ; i <<= 1 ) {
		for ( j = 0 ; j < size ; j += 2*i ) {
			for ( k = 0 ; k < i ; k ++ ) {
				a = mulc(ret[j+k+i],w_list[k*kstep]);
				b = addc(ret[j+k],a);
				c = subc(ret[j+k],a);
				ret[j+k] = b;
				ret[j+k+i] = c;
			}
		}
		kstep = kstep >> 1;
	}
	return ret;
}

COMPLEX *
fastft(COMPLEX * list,int beki)
{
COMPLEX * ret;
int size;
double a;
int i;
	size = 1<<beki;
	ret = _fastft(list,beki,-1);
	a = 1/(double)size;
	for ( i = 0 ; i < size ; i ++ ) {
		ret[i].re *= a;
		ret[i].im *= a;
	}
	return ret;
}

COMPLEX *
fastdft(COMPLEX * list,int beki)
{
	return _fastft(list,beki,1);
}
