Just another update
This commit is contained in:
parent
a25938f123
commit
00a190b0a6
6591 changed files with 94363 additions and 23227 deletions
|
|
@ -1 +1,10 @@
|
|||
The purpose of this task is to calculate the FFT (Fast Fourier Transform) of an input sequence. The most general case allows for complex numbers at the input and results in a sequence of equal length, again of complex numbers. If you need to restrict yourself to real numbers the output should be the magnitude (i.e. sqrt(re²+im²)) of the complex result. The classic version is the recursive Cooley–Tukey FFT. [http://en.wikipedia.org/wiki/Cooley–Tukey_FFT_algorithm Wikipedia] has pseudocode for that. Further optimizations are possible but not required.
|
||||
{{omit from|GUISS}}
|
||||
The purpose of this task is to calculate the FFT (Fast Fourier Transform)
|
||||
of an input sequence. <br>
|
||||
The most general case allows for complex numbers at the input
|
||||
and results in a sequence of equal length, again of complex numbers.
|
||||
If you need to restrict yourself to real numbers, the output should
|
||||
be the magnitude (i.e. sqrt(re²+im²)) of the complex result.
|
||||
|
||||
The classic version is the recursive Cooley–Tukey FFT. [http://en.wikipedia.org/wiki/Cooley–Tukey_FFT_algorithm Wikipedia] has pseudocode for that.
|
||||
Further optimizations are possible but not required.
|
||||
|
|
|
|||
50
Task/Fast-Fourier-transform/C/fast-fourier-transform.c
Normal file
50
Task/Fast-Fourier-transform/C/fast-fourier-transform.c
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <complex.h>
|
||||
|
||||
double PI;
|
||||
typedef double complex cplx;
|
||||
|
||||
void _fft(cplx buf[], cplx out[], int n, int step)
|
||||
{
|
||||
if (step < n) {
|
||||
_fft(out, buf, n, step * 2);
|
||||
_fft(out + step, buf + step, n, step * 2);
|
||||
|
||||
for (int i = 0; i < n; i += 2 * step) {
|
||||
cplx t = cexp(-I * PI * i / n) * out[i + step];
|
||||
buf[i / 2] = out[i] + t;
|
||||
buf[(i + n)/2] = out[i] - t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fft(cplx buf[], int n)
|
||||
{
|
||||
cplx out[n];
|
||||
for (int i = 0; i < n; i++) out[i] = buf[i];
|
||||
|
||||
_fft(buf, out, n, 1);
|
||||
}
|
||||
|
||||
|
||||
void show(const char * s, cplx buf[]) {
|
||||
printf("%s", s);
|
||||
for (int i = 0; i < 8; i++)
|
||||
if (!cimag(buf[i]))
|
||||
printf("%g ", creal(buf[i]));
|
||||
else
|
||||
printf("(%g, %g) ", creal(buf[i]), cimag(buf[i]));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
PI = atan2(1, 1) * 4;
|
||||
cplx buf[] = {1, 1, 1, 1, 0, 0, 0, 0};
|
||||
|
||||
show("Data: ", buf);
|
||||
fft(buf, 8);
|
||||
show("\nFFT : ", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import std.stdio, std.numeric;
|
||||
|
||||
void main() {
|
||||
import std.stdio, std.numeric;
|
||||
|
||||
[1.0, 1, 1, 1, 0, 0, 0, 0].fft.writeln;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import std.stdio, std.algorithm, std.range, std.math;
|
||||
|
||||
const(creal)[] fft(in creal[] x) /*pure nothrow*/ {
|
||||
const(creal)[] fft(in creal[] x) pure /*nothrow*/ @safe {
|
||||
immutable N = x.length;
|
||||
if (N <= 1) return x;
|
||||
const ev = x.stride(2).array.fft;
|
||||
|
|
@ -10,6 +10,6 @@ const(creal)[] fft(in creal[] x) /*pure nothrow*/ {
|
|||
return l.chain(r).array;
|
||||
}
|
||||
|
||||
void main() {
|
||||
void main() @safe {
|
||||
[1.0L+0i, 1, 1, 1, 0, 0, 0, 0].fft.writeln;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import std.stdio, std.algorithm, std.range, std.math, std.complex;
|
||||
|
||||
auto fft(T)(in T[] x) /*pure nothrow*/ {
|
||||
auto fft(T)(in T[] x) pure /*nothrow @safe*/ {
|
||||
immutable N = x.length;
|
||||
if (N <= 1) return x;
|
||||
const ev = x.stride(2).array.fft;
|
||||
const od = x[1 .. $].stride(2).array.fft;
|
||||
alias E = std.complex.expi;
|
||||
auto l = iota(N / 2).map!(k=> ev[k] + cast(T)E(-2*PI*k/N) * od[k]);
|
||||
auto r = iota(N / 2).map!(k=> ev[k] - cast(T)E(-2*PI*k/N) * od[k]);
|
||||
auto l = iota(N / 2).map!(k => ev[k] + T(E(-2* PI * k/N)) * od[k]);
|
||||
auto r = iota(N / 2).map!(k => ev[k] - T(E(-2* PI * k/N)) * od[k]);
|
||||
return l.chain(r).array;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
complex fast fourier transform and inverse from
|
||||
http://rosettacode.org/wiki/Fast_Fourier_transform#C.2B.2B
|
||||
*/
|
||||
function icfft(amplitudes)
|
||||
{
|
||||
var N = amplitudes.length;
|
||||
var iN = 1 / N;
|
||||
|
||||
//conjugate if imaginary part is not 0
|
||||
for(var i = 0 ; i < N; ++i)
|
||||
if(amplitudes[i] instanceof Complex)
|
||||
amplitudes[i].im = -amplitudes[i].im;
|
||||
|
||||
//apply fourier transform
|
||||
amplitudes = cfft(amplitudes)
|
||||
|
||||
for(var i = 0 ; i < N; ++i)
|
||||
{
|
||||
//conjugate again
|
||||
amplitudes[i].im = -amplitudes[i].im;
|
||||
//scale
|
||||
amplitudes[i].re *= iN;
|
||||
amplitudes[i].im *= iN;
|
||||
}
|
||||
return amplitudes;
|
||||
}
|
||||
|
||||
function cfft(amplitudes)
|
||||
{
|
||||
var N = amplitudes.length;
|
||||
if( N <= 1 )
|
||||
return amplitudes;
|
||||
|
||||
var hN = N / 2;
|
||||
var even = [];
|
||||
var odd = [];
|
||||
even.length = hN;
|
||||
odd.length = hN;
|
||||
for(var i = 0; i < hN; ++i)
|
||||
{
|
||||
even[i] = amplitudes[i*2];
|
||||
odd[i] = amplitudes[i*2+1];
|
||||
}
|
||||
even = cfft(even);
|
||||
odd = cfft(odd);
|
||||
|
||||
var a = -2*Math.PI;
|
||||
for(var k = 0; k < hN; ++k)
|
||||
{
|
||||
if(!(even[k] instanceof Complex))
|
||||
even[k] = new Complex(even[k], 0);
|
||||
if(!(odd[k] instanceof Complex))
|
||||
odd[k] = new Complex(odd[k], 0);
|
||||
var p = k/N;
|
||||
var t = new Complex(0, a * p);
|
||||
t.cexp(t).mul(odd[k], t);
|
||||
amplitudes[k] = even[k].add(t, odd[k]);
|
||||
amplitudes[k + hN] = even[k].sub(t, even[k]);
|
||||
}
|
||||
return amplitudes;
|
||||
}
|
||||
|
||||
//test code
|
||||
//console.log( cfft([1,1,1,1,0,0,0,0]) );
|
||||
//console.log( icfft(cfft([1,1,1,1,0,0,0,0])) );
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
basic complex number arithmetic from
|
||||
http://rosettacode.org/wiki/Fast_Fourier_transform#Scala
|
||||
*/
|
||||
function Complex(re, im)
|
||||
{
|
||||
this.re = re;
|
||||
this.im = im || 0.0;
|
||||
}
|
||||
Complex.prototype.add = function(other, dst)
|
||||
{
|
||||
dst.re = this.re + other.re;
|
||||
dst.im = this.im + other.im;
|
||||
return dst;
|
||||
}
|
||||
Complex.prototype.sub = function(other, dst)
|
||||
{
|
||||
dst.re = this.re - other.re;
|
||||
dst.im = this.im - other.im;
|
||||
return dst;
|
||||
}
|
||||
Complex.prototype.mul = function(other, dst)
|
||||
{
|
||||
//cache re in case dst === this
|
||||
var r = this.re * other.re - this.im * other.im;
|
||||
dst.im = this.re * other.im + this.im * other.re;
|
||||
dst.re = r;
|
||||
return dst;
|
||||
}
|
||||
Complex.prototype.cexp = function(dst)
|
||||
{
|
||||
var er = Math.exp(this.re);
|
||||
dst.re = er * Math.cos(this.im);
|
||||
dst.im = er * Math.sin(this.im);
|
||||
return dst;
|
||||
}
|
||||
Complex.prototype.log = function()
|
||||
{
|
||||
/*
|
||||
although 'It's just a matter of separating out the real and imaginary parts of jw.' is not a helpful quote
|
||||
the actual formula I found here and the rest was just fiddling / testing and comparing with correct results.
|
||||
http://cboard.cprogramming.com/c-programming/89116-how-implement-complex-exponential-functions-c.html#post637921
|
||||
*/
|
||||
if( !this.re )
|
||||
console.log(this.im.toString()+'j');
|
||||
else if( this.im < 0 )
|
||||
console.log(this.re.toString()+this.im.toString()+'j');
|
||||
else
|
||||
console.log(this.re.toString()+'+'+this.im.toString()+'j');
|
||||
}
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
sub fft {
|
||||
return @_ if @_ == 1;
|
||||
my @evn = fft( @_[0,2...^* >= @_] );
|
||||
my @odd = fft( @_[1,3...^* >= @_] );
|
||||
my $twd = 2i * pi / @_; # twiddle factor
|
||||
@odd[$_] *= exp( $_ * $twd ) for ^@odd;
|
||||
my @evn = fft( @_[0, 2 ... *] );
|
||||
my @odd = fft( @_[1, 3 ... *] ) Z*
|
||||
(1, * * cis( 2 * pi / @_ ) ... *);
|
||||
return @evn »+« @odd, @evn »-« @odd;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ use Math::Complex;
|
|||
|
||||
sub fft {
|
||||
return @_ if @_ == 1;
|
||||
my @evn = fft(@_[grep { not $_ % 2 } 0 .. @_ - 1]);
|
||||
my @odd = fft(@_[grep { $_ % 2 } 1 .. @_ - 1]);
|
||||
my @evn = fft(@_[grep { not $_ % 2 } 0 .. $#_ ]);
|
||||
my @odd = fft(@_[grep { $_ % 2 } 1 .. $#_ ]);
|
||||
my $twd = 2*i* pi / @_;
|
||||
$odd[$_] *= exp( $_ * $twd ) for 0 .. @odd - 1;
|
||||
$odd[$_] *= exp( $_ * $twd ) for 0 .. $#odd;
|
||||
return
|
||||
(map { $evn[$_] + $odd[$_] } 0 .. @evn-1 ),
|
||||
(map { $evn[$_] - $odd[$_] } 0 .. @evn-1 );
|
||||
(map { $evn[$_] + $odd[$_] } 0 .. $#evn ),
|
||||
(map { $evn[$_] - $odd[$_] } 0 .. $#evn );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ from cmath import exp, pi
|
|||
def fft(x):
|
||||
N = len(x)
|
||||
if N <= 1: return x
|
||||
even = fft(x[0::2])
|
||||
odd = fft(x[1::2])
|
||||
return [even[k] + exp(-2j*pi*k/N)*odd[k] for k in xrange(N/2)] + \
|
||||
[even[k] - exp(-2j*pi*k/N)*odd[k] for k in xrange(N/2)]
|
||||
even = fft2(x[0::2])
|
||||
odd = fft2(x[1::2])
|
||||
T= [exp(-2j*pi*k/N)*odd[k] for k in xrange(N/2)]
|
||||
return [even[k] + T[k] for k in xrange(N/2)] + \
|
||||
[even[k] - T[k] for k in xrange(N/2)]
|
||||
|
||||
print fft([1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0])
|
||||
print( ' '.join("%5.3f" % abs(f)
|
||||
for f in fft([1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0])) )
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
>>> from numpy.fft import fft
|
||||
>>> from numpy import array
|
||||
>>> a = array((0.0, 0.924, 0.707, -0.383, -1.0, -0.383, 0.707, 0.924, 0.0, -0.924, -0.707, 0.383, 1.0, 0.383, -0.707, -0.924))
|
||||
>>> a = array([1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0])
|
||||
>>> print( ' '.join("%5.3f" % abs(f) for f in fft(a)) )
|
||||
0.000 0.001 0.000 8.001 0.000 0.001 0.000 0.001 0.000 0.001 0.000 0.001 0.000 8.001 0.000 0.001
|
||||
4.000 2.613 0.000 1.082 0.000 1.082 0.000 2.613
|
||||
|
|
|
|||
|
|
@ -1,56 +1,60 @@
|
|||
/*REXX pgm does a fast Fourier transform (FFT) on a set of complex nums.*/
|
||||
numeric digits length( pi() ) - 1 /*limited by PI function result. */
|
||||
arg data; if data='' then data='1 1 1 1 0' /*no data? Then use default*/
|
||||
data=translate(data, 'J', "I") /*allow use of i as well as j */
|
||||
arg data /*the ARG verb uppercases DATA */
|
||||
if data='' then data=1 1 1 1 0 /*No data? Then use the default.*/
|
||||
data=translate(data, 'J', "I") /*allow use of I as well as J */
|
||||
size=words(data); pad=left('',6) /*PAD: for indenting/padding SAYs*/
|
||||
do sig=0 until 2**sig>=size ;end /* # args exactly a power of 2?*/
|
||||
do j=size+1 to 2**sig;data=data 0;end /*add zeroes until a power of 2.*/
|
||||
size=words(data); call hdr /*┌─────────────────────────────┐*/
|
||||
do p=0 until 2**p>=size ; end /* # args exactly a power of 2? */
|
||||
do j=size+1 to 2**p;data=data 0; end /*add zeroes until a power of 2. */
|
||||
size=words(data); ph=p%2; call hdr /*┌─────────────────────────────┐*/
|
||||
/*│ Numbers in data can be in │*/
|
||||
do j=0 for size /*│ 7 formats: real │*/
|
||||
_=word(data,j+1) /*│ real,imag │*/
|
||||
parse var _ #.1.j ',' #.2.j /*│ ,imag │*/
|
||||
if right(#.1.j,1)=='J' then /*│ nnnJ │*/
|
||||
parse var #.1.j #2.j "J" @.1.j /*│ nnnj │*/
|
||||
do p=1 for 2 /*omitted?*/ /*│ nnnI │*/
|
||||
#.p.j=word(#.p.j 0, 1) /*│ nnni │*/
|
||||
end /*p*/ /*└─────────────────────────────┘*/
|
||||
parse var _ #.1.j ',' #.2.j /*│ ,imag │*/
|
||||
if right(#.1.j,1)=='J' then parse , /*│ nnnJ │*/
|
||||
var #.1.j #2.j "J" @.1.j /*│ nnnj │*/
|
||||
do m=1 for 2 /*omitted?*/ /*│ nnnI │*/
|
||||
#.m.j=word(#.m.j 0, 1) /*│ nnni │*/
|
||||
end /*m*/ /*└─────────────────────────────┘*/
|
||||
|
||||
say pad " FFT in " center(j+1,7) pad nice(#.1.j) nice(#.2.j,'i')
|
||||
end /*j*/
|
||||
|
||||
say; say; tran=2*pi()/2**sig; !.=0
|
||||
hsig=2**sig%2; counterA=2**(sig-sig%2); pointer=counterA; doubler=1
|
||||
say; say; tran=2*pi()/2**p; !.=0
|
||||
hp=2**p%2; counterA=2**(p-ph); pointer=counterA; doubler=1
|
||||
|
||||
do p-ph; halfpointer=pointer%2
|
||||
|
||||
do sig-sig%2; halfpointer=pointer%2
|
||||
do i=halfpointer by pointer to counterA-halfpointer
|
||||
_=i-halfpointer; !.i=!._+doubler
|
||||
_=i-halfpointer; !.i=!._+doubler
|
||||
end /*i*/
|
||||
doubler=doubler*2; pointer=halfpointer
|
||||
end /*sig-sig%2*/
|
||||
|
||||
do j=0 to 2**sig%4; cmp.j=cos(j*tran); _m=hsig-j; cmp._m=-cmp.j
|
||||
_p=hsig+j; cmp._p=-cmp.j
|
||||
end /*j*/
|
||||
doubler=doubler*2; pointer=halfpointer
|
||||
end /*p-ph*/
|
||||
|
||||
counterB=2**(sig%2)
|
||||
do j=0 to 2**p%4; cmp.j=cos(j*tran); _m=hp-j; cmp._m=-cmp.j
|
||||
_p=hp+j; cmp._p=-cmp.j
|
||||
end /*j*/
|
||||
|
||||
do i=0 for counterA; p=i*counterB
|
||||
do j=0 for counterB; h=p+j; _=!.j*counterB+!.i; if _<=h then iterate
|
||||
counterB=2**ph
|
||||
|
||||
do i=0 for counterA; q=i *counterB
|
||||
do j=0 for counterB; h=q+j; _=!.j*counterB+!.i; if _<=h then iterate
|
||||
parse value #.1._ #.1.h #.2._ #.2.h with #.1.h #.1._ #.2.h #.2._
|
||||
end /*j*/ /* [↓] switch two sets of values*/
|
||||
end /*j*/ /* [↑] switch two sets of values*/
|
||||
end /*i*/
|
||||
|
||||
double=1; do sig ; w=2**sig%2%double
|
||||
do k=0 for double ; lb=w*k ; lh=lb+2**sig%4
|
||||
do j=0 for w ; a=j*double*2+k ; b=a+double
|
||||
r=#.1.a; i=#.2.a ; c1=cmp.lb*#.1.b ; c4=cmp.lb*#.2.b
|
||||
c2=cmp.lh*#.2.b ; c3=cmp.lh*#.1.b
|
||||
#.1.a=r+c1-c2 ; #.2.a=i+c3+c4
|
||||
#.1.b=r-c1+c2 ; #.2.b=i-c3-c4
|
||||
double=1; do p ; w=hp%double
|
||||
do k=0 for double; lb=w*k ; lh=lb+2**p%4
|
||||
do j=0 for w ; a=j*double*2+k ; b=a+double
|
||||
r=#.1.a; i=#.2.a ; c1=cmp.lb*#.1.b ; c4=cmp.lb*#.2.b
|
||||
c2=cmp.lh*#.2.b ; c3=cmp.lh*#.1.b
|
||||
#.1.a=r+c1-c2 ; #.2.a=i+c3+c4
|
||||
#.1.b=r-c1+c2 ; #.2.b=i-c3-c4
|
||||
end /*j*/
|
||||
end /*k*/
|
||||
double=double+double
|
||||
end /*sig*/
|
||||
end /*p*/
|
||||
call hdr
|
||||
do i=0 for size
|
||||
say pad " FFT out " center(i+1,7) pad nice(#.1.i) nice(#.2.i,'j')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
#lang racket
|
||||
(require math)
|
||||
(array-fft (array #[1. 1. 1. 1. 0. 0. 0. 0.]))
|
||||
|
|
@ -3,8 +3,8 @@ def fft(vec)
|
|||
evens_odds = vec.partition.with_index{|_,i| i.even?}
|
||||
evens, odds = evens_odds.map{|even_odd| fft(even_odd)*2}
|
||||
evens.zip(odds).map.with_index do |(even, odd),i|
|
||||
even + odd * Math::E ** Complex(0, 2 * Math::PI * (-i)/ vec.size)
|
||||
even + odd * Math::E ** Complex(0, -2 * Math::PI * i / vec.size)
|
||||
end
|
||||
end
|
||||
|
||||
fft([1,1,1,1,0,0,0,0]).each{|c| p c}
|
||||
fft([1,1,1,1,0,0,0,0]).each{|c| puts "%9.6f %+9.6fi" % c.rect}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
import scala.math.{ Pi, cos, sin, cosh, sinh, abs }
|
||||
|
||||
case class Complex(re: Double, im: Double) {
|
||||
def +(x: Complex): Complex = Complex(re + x.re, im + x.im)
|
||||
def -(x: Complex): Complex = Complex(re - x.re, im - x.im)
|
||||
def *(x: Double): Complex = Complex(re * x, im * x)
|
||||
def *(x: Complex): Complex = Complex(re * x.re - im * x.im, re * x.im + im * x.re)
|
||||
def /(x: Double): Complex = Complex(re / x, im / x)
|
||||
|
||||
override def toString(): String = {
|
||||
val a = "%1.3f" format re
|
||||
val b = "%1.3f" format abs(im)
|
||||
(a,b) match {
|
||||
case (_, "0.000") => a
|
||||
case ("0.000", _) => b + "i"
|
||||
case (_, _) if im > 0 => a + " + " + b + "i"
|
||||
case (_, _) => a + " - " + b + "i"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def exp(c: Complex) : Complex = {
|
||||
val r = (cosh(c.re) + sinh(c.re))
|
||||
Complex(cos(c.im), sin(c.im)) * r
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
def _fft(cSeq: Seq[Complex], direction: Complex, scalar: Int): Seq[Complex] = {
|
||||
if (cSeq.length == 1) {
|
||||
return cSeq
|
||||
}
|
||||
val n = cSeq.length
|
||||
assume(n % 2 == 0, "The Cooley-Tukey FFT algorithm only works when the length of the input is even.")
|
||||
|
||||
val evenOddPairs = cSeq.grouped(2).toSeq
|
||||
val evens = _fft(evenOddPairs map (_(0)), direction, scalar)
|
||||
val odds = _fft(evenOddPairs map (_(1)), direction, scalar)
|
||||
|
||||
def leftRightPair(k: Int): Pair[Complex, Complex] = {
|
||||
val base = evens(k) / scalar
|
||||
val offset = exp(direction * (Pi * k / n)) * odds(k) / scalar
|
||||
(base + offset, base - offset)
|
||||
}
|
||||
|
||||
val pairs = (0 until n/2) map leftRightPair
|
||||
val left = pairs map (_._1)
|
||||
val right = pairs map (_._2)
|
||||
left ++ right
|
||||
}
|
||||
|
||||
def fft(cSeq: Seq[Complex]): Seq[Complex] = _fft(cSeq, Complex(0, 2), 1)
|
||||
def rfft(cSeq: Seq[Complex]): Seq[Complex] = _fft(cSeq, Complex(0, -2), 2)
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
val data = Seq(Complex(1,0), Complex(1,0), Complex(1,0), Complex(1,0),
|
||||
Complex(0,0), Complex(0,2), Complex(0,0), Complex(0,0))
|
||||
|
||||
println(fft(data))
|
||||
println(rfft(fft(data)))
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
object FFT extends App {
|
||||
import scala.math._
|
||||
|
||||
case class Complex(re: Double, im: Double = 0.0) {
|
||||
def +(x: Complex): Complex = Complex((this.re+x.re),(this.im+x.im))
|
||||
def -(x: Complex): Complex = Complex((this.re-x.re),(this.im-x.im))
|
||||
def *(x: Complex): Complex = Complex(this.re*x.re-this.im*x.im,this.re*x.im+this.im*x.re)
|
||||
}
|
||||
|
||||
def fft(f: List[Complex]): List[Complex] = {
|
||||
import Stream._
|
||||
require((f.size==0)||(from(0) map {x=>pow(2,x).toInt}).takeWhile(_<2*f.size).toList.exists(_==f.size)==true,"list size "+f.size+" not allowed!")
|
||||
f.size match {
|
||||
case 0 => Nil
|
||||
case 1 => f
|
||||
case n => {
|
||||
val cis: Double => Complex = phi => Complex(cos(phi),sin(phi))
|
||||
val e = fft(f.zipWithIndex.filter(_._2%2==0).map(_._1))
|
||||
val o = fft(f.zipWithIndex.filter(_._2%2!=0).map(_._1))
|
||||
import scala.collection.mutable.ListBuffer
|
||||
val lb = new ListBuffer[Pair[Int, Complex]]()
|
||||
for (k <- 0 to n/2-1) {
|
||||
lb += Pair(k,e(k)+o(k)*cis(-2*Pi*k/n))
|
||||
lb += Pair(k+n/2,e(k)-o(k)*cis(-2*Pi*k/n))
|
||||
}
|
||||
lb.toList.sortWith((x,y)=>x._1<y._1).map(_._2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fft(List(Complex(1),Complex(1),Complex(1),Complex(1),Complex(0),Complex(0),Complex(0),Complex(0))).foreach(println)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue