|
|
@ -2,6 +2,14 @@ |
|
|
|
|
|
|
|
use number::{Complex, c64};
|
|
|
|
|
|
|
|
macro_rules! reinterpret(
|
|
|
|
($data:ident) => (unsafe {
|
|
|
|
use std::slice::from_raw_parts_mut;
|
|
|
|
let n = power_of_two!($data);
|
|
|
|
(from_raw_parts_mut($data.as_mut_ptr() as *mut _, n / 2), n / 2)
|
|
|
|
});
|
|
|
|
);
|
|
|
|
|
|
|
|
/// Perform the forward transform.
|
|
|
|
///
|
|
|
|
/// The number of points should be a power of two. The data are replaced by the
|
|
|
@ -15,46 +23,24 @@ use number::{Complex, c64}; |
|
|
|
/// Flannery, “Numerical Recipes 3rd Edition: The Art of Scientific
|
|
|
|
/// Computing,” Cambridge University Press, 2007.
|
|
|
|
pub fn forward(data: &mut [f64]) {
|
|
|
|
use std::f64::consts::PI;
|
|
|
|
use std::slice::from_raw_parts_mut;
|
|
|
|
|
|
|
|
let (data, n) = unsafe {
|
|
|
|
let n = data.len();
|
|
|
|
power_of_two!(n);
|
|
|
|
(from_raw_parts_mut(data.as_mut_ptr() as *mut _, n / 2), n / 2)
|
|
|
|
};
|
|
|
|
|
|
|
|
let (data, n) = reinterpret!(data);
|
|
|
|
::complex::forward(data);
|
|
|
|
compose(data, n, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
let (multiplier, mut factor) = {
|
|
|
|
let delta = -PI / n as f64;
|
|
|
|
let sine = (0.5 * delta).sin();
|
|
|
|
(c64(-2.0 * sine * sine, delta.sin()), c64(0.0, 1.0))
|
|
|
|
};
|
|
|
|
|
|
|
|
data[0] = c64(
|
|
|
|
data[0].re() + data[0].im(),
|
|
|
|
data[0].re() - data[0].im(),
|
|
|
|
);
|
|
|
|
|
|
|
|
for i in 1..(n / 2) {
|
|
|
|
let j = n - i;
|
|
|
|
|
|
|
|
factor = multiplier * factor + factor;
|
|
|
|
let part1 = (data[i] + data[j].conj()) * 0.5;
|
|
|
|
let part2 = -(data[i] - data[j].conj()) * 0.5;
|
|
|
|
|
|
|
|
data[i] = part1 + factor * part2;
|
|
|
|
data[j] = (part1 - factor * part2).conj();
|
|
|
|
}
|
|
|
|
|
|
|
|
data[n / 2] = data[n / 2].conj();
|
|
|
|
/// Perform the inverse transform.
|
|
|
|
///
|
|
|
|
/// The number of points should be a power of two. The data should be packed as
|
|
|
|
/// described in `real::forward`.
|
|
|
|
pub fn inverse(data: &mut [f64], scaling: bool) {
|
|
|
|
let (data, n) = reinterpret!(data);
|
|
|
|
compose(data, n, true);
|
|
|
|
::complex::inverse(data, scaling);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Unpack a compressed representation produced by `real::forward`.
|
|
|
|
pub fn unpack(data: &[f64]) -> Vec<c64> {
|
|
|
|
let n = data.len();
|
|
|
|
power_of_two!(n);
|
|
|
|
let n = power_of_two!(data);
|
|
|
|
|
|
|
|
let mut cdata = Vec::with_capacity(n);
|
|
|
|
unsafe { cdata.set_len(n) };
|
|
|
@ -71,6 +57,35 @@ pub fn unpack(data: &[f64]) -> Vec<c64> { |
|
|
|
cdata
|
|
|
|
}
|
|
|
|
|
|
|
|
fn compose(data: &mut [c64], n: usize, inverse: bool) {
|
|
|
|
use std::f64::consts::PI;
|
|
|
|
|
|
|
|
data[0] = c64(data[0].re() + data[0].im(), data[0].re() - data[0].im());
|
|
|
|
if inverse {
|
|
|
|
data[0] = data[0] * 0.5;
|
|
|
|
}
|
|
|
|
|
|
|
|
let (multiplier, mut factor) = {
|
|
|
|
let sign = if inverse { 1.0 } else { -1.0 };
|
|
|
|
let delta = sign * PI / n as f64;
|
|
|
|
let sine = (0.5 * delta).sin();
|
|
|
|
(c64(-2.0 * sine * sine, delta.sin()), c64(0.0, -sign))
|
|
|
|
};
|
|
|
|
|
|
|
|
for i in 1..(n / 2) {
|
|
|
|
let j = n - i;
|
|
|
|
|
|
|
|
let part1 = (data[i] + data[j].conj()) * 0.5;
|
|
|
|
let part2 = -(data[i] - data[j].conj()) * 0.5;
|
|
|
|
|
|
|
|
factor = multiplier * factor + factor;
|
|
|
|
data[i] = part1 + factor * part2;
|
|
|
|
data[j] = (part1 - factor * part2).conj();
|
|
|
|
}
|
|
|
|
|
|
|
|
data[n / 2] = data[n / 2].conj();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use number::c64;
|
|
|
|