use num;
use strided::{Stride, MutStride};
use std::f64::consts::PI;
use {Precision, Complex, ComplexMut};
fn fft<CI: Complex, CO: ComplexMut>(direction: Precision, input: Stride<CI>, mut output: MutStride<CO>) {
let length = input.len();
if length == 1 {
output[0].set(&input[0]);
return;
}
let (evens, odds) = input.substrides2();
let (mut left, mut right) = output.split_at_mut(length >> 1);
fft(direction, evens, left.reborrow());
fft(direction, odds, right.reborrow());
let twiddle = num::Complex::from_polar(&1.0,
&(direction * PI as Precision / length as Precision));
let mut factor = num::Complex::new(1.0, 0.0);
for (even, odd) in left.iter_mut().zip(right.iter_mut()) {
let twiddled = factor * odd.to_num();
let e = even.to_num();
even.set(&(e + twiddled));
odd.set(&(e - twiddled));
factor = factor * twiddle;
}
}
#[inline(always)]
pub fn forward<CI: Complex, CO: ComplexMut>(input: Stride<CI>, output: MutStride<CO>) {
debug_assert_eq!(input.len(), output.len());
debug_assert!(input.len().is_power_of_two(), "length is not a power of two");
fft(-2.0, input, output);
}
#[inline(always)]
pub fn inverse<CI: Complex, CO: ComplexMut>(input: Stride<CI>, output: MutStride<CO>) {
debug_assert_eq!(input.len(), output.len());
debug_assert!(input.len().is_power_of_two(), "length is not a power of two");
fft(2.0, input, output);
}
#[cfg(test)]
mod tests {
use num::Complex;
use strided::{Stride, MutStrided};
use ::ComplexMut;
macro_rules! fix {
($a:expr) => (
if $a == "-0.00" {
"0.00".to_owned()
}
else {
$a
}
)
}
macro_rules! assert_approx_eq {
($a:expr, $b:expr) => (
assert_eq!(fix!(format!("{:.2}", $a.re)), fix!(format!("{:.2}", $b.re)));
assert_eq!(fix!(format!("{:.2}", $a.im)), fix!(format!("{:.2}", $b.im)));
)
}
#[test]
fn forward() {
let mut output = vec![Complex::new(0.0, 0.0); 4];
super::forward(Stride::new(&[1.0, 1.0, 0.0, 0.0]), output.as_stride_mut());
assert_approx_eq!(output[0], Complex::new(2.00, 0.00));
assert_approx_eq!(output[1], Complex::new(1.00, -1.00));
assert_approx_eq!(output[2], Complex::new(0.00, 0.00));
assert_approx_eq!(output[3], Complex::new(1.00, 1.00));
}
#[test]
fn inverse() {
let mut output = vec![Complex::new(0.0, 0.0); 4];
super::inverse(Stride::new(&[1.0, 1.0, 0.0, 0.0]), output.as_stride_mut());
for output in output.iter_mut() {
ComplexMut::unscale(output, 4.0);
}
assert_approx_eq!(output[0], Complex::new(0.50, 0.00));
assert_approx_eq!(output[1], Complex::new(0.25, 0.25));
assert_approx_eq!(output[2], Complex::new(0.00, 0.00));
assert_approx_eq!(output[3], Complex::new(0.25, -0.25));
}
}