Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 54 additions & 71 deletions chapters/FFT/code/c/fft.c
Original file line number Diff line number Diff line change
@@ -1,105 +1,88 @@
// written by Gathros.

#include <complex.h>
#include <math.h>

// These headers are for presentation not for the algorithm.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>

#define PI 3.1415926535897932384626

void cooley_tukey(double complex *X, const size_t N){
if(N >= 2){
// Splits the array, so the top half are the odd elements and the bottom half are the even ones.
double complex tmp [N/2];
for(size_t i = 0; i < N/2; ++i){
tmp[i] = X[2*i + 1];
X[i] = X[2*i];
}
for(size_t i = 0; i < N/2; ++i){
X[i + N/2] = tmp[i];
}
void cooley_tukey(double complex *X, const size_t N) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This N is the only parameter which is const, which is quite odd.

if (N >= 2) {
double complex tmp [N / 2];
for (size_t i = 0; i < N / 2; ++i) {
tmp[i] = X[2*i + 1];
X[i] = X[2*i];
}
for (size_t i = 0; i < N / 2; ++i) {
X[i + N / 2] = tmp[i];
}

// Recursion.
cooley_tukey(X, N/2);
cooley_tukey(X + N/2, N/2);
cooley_tukey(X, N / 2);
cooley_tukey(X + N / 2, N / 2);

// Combine.
for(size_t i = 0; i < N/2; ++i){
X[i + N/2] = X[i] - cexp(-2.0*I*PI*i/N)*X[i + N/2];
X[i] -= (X[i + N/2]-X[i]);
}
}
for (size_t i = 0; i < N / 2; ++i) {
X[i + N / 2] = X[i] - cexp(-2.0 * I * PI * i / N) * X[i + N / 2];
X[i] -= (X[i + N / 2]-X[i]);
}
}
}

void bit_reverse(double complex *X, size_t N){
// Bit reverses the array X[] but only if the size of the array is less then 2^32.
double complex temp;
void bit_reverse(double complex *X, size_t N) {
double complex temp;
unsigned int b;

for(unsigned int i = 0; i < N; ++i){
for (unsigned int i = 0; i < N; ++i) {
b = i;
b = (((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1));
b = (((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2));
b = (((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4));
b = (((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8));
b = ((b >> 16) | (b << 16)) >> (32 - (unsigned int) log2((double)N));
if(b > i){
b = ((b >> 16) | (b << 16)) >>
(32 - (unsigned int) log2((double)N));
if (b > i) {
temp = X[b];
X[b] = X[i];
X[i] = temp;
}
}
}

void iterative_cooley_tukey(double complex *X, size_t N){
int stride;
double complex v,w;

// Bit reverse the array.
bit_reverse(X, N);

// Preform the butterfly on the array.
for(int i = 1; i <= log2((double)N); ++i){
stride = pow(2, i);
w = cexp(-2.0*I*PI/stride);
for(size_t j = 0; j < N; j += stride){
v = 1.0;
for(size_t k = 0; k < stride/2; k++){
X[k + j + stride/2] = X[k + j] - v*X[k + j + stride/2];
X[k + j] -= (X[k + j + stride/2] - X[k + j]);
v *= w;
}
}
}
void iterative_cooley_tukey(double complex *X, size_t N) {
bit_reverse(X, N);

for (int i = 1; i <= log2((double)N); ++i) {
int stride = pow(2, i);
double complex w = cexp(-2.0 * I * PI / stride);
for (size_t j = 0; j < N; j += stride) {
double complex v = 1.0;
for (size_t k = 0; k < stride / 2; ++k) {
X[k + j + stride / 2] = X[k + j] - v * X[k + j + stride / 2];
X[k + j] -= (X[k + j + stride / 2] - X[k + j]);
v *= w;
}
}
}
}

void approx(double complex *X, double complex *Y, size_t N){
// This is to show that the arrays are approximate.
for(size_t i = 0; i < N; ++i){
printf("%f\n", cabs(X[i]) - cabs(Y[i]));
}
void approx(double complex *X, double complex *Y, size_t N) {
for (size_t i = 0; i < N; ++i) {
printf("%f\n", cabs(X[i]) - cabs(Y[i]));
}
}

int main(){
// Initalizing the arrays for FFT.
srand(time(NULL));
const size_t N = 64;
double complex x[N], y[N], z[N];
for(size_t i = 0; i < N; ++i){
x[i] = rand() / (double) RAND_MAX;
y[i] = x[i];
z[i] = x[i];
}
int main() {
srand(time(NULL));
double complex x[64], y[64], z[64];
for (size_t i = 0; i < 64; ++i) {
x[i] = rand() / (double) RAND_MAX;
y[i] = x[i];
z[i] = x[i];
}

// Preform FFT.
cooley_tukey(y, N);
iterative_cooley_tukey(z, N);
cooley_tukey(y, 64);
iterative_cooley_tukey(z, 64);

// Check if the different methods are approximate.
approx(y, z, N);
approx(y, z, 64);

return 0;
return 0;
}
68 changes: 35 additions & 33 deletions chapters/convolutions/code/c/convolutions.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,49 @@

#include <math.h>

void fft(double complex *X, size_t N){
if(N >= 2){
// Splits the array, so the top half are the odd elements and the bottom half are the even ones.
double complex tmp [N/2];
for(size_t i = 0; i < N/2; ++i){
tmp[i] = X[2*i + 1];
X[i] = X[2*i];
void fft(double complex *X, size_t N) {
if (N >= 2) {
double complex tmp [N / 2];
for (size_t i = 0; i < N / 2; ++i) {
tmp[i] = X[2 * i + 1];
X[i] = X[2 * i];
}
for(size_t i = 0; i < N/2; ++i){
X[i + N/2] = tmp[i];

for (size_t i = 0; i < N / 2; ++i) {
X[i + N / 2] = tmp[i];
}

// Recursion.
fft(X, N/2);
fft(X + N/2, N/2);
fft(X, N / 2);
fft(X + N / 2, N / 2);

// Combine.
for(size_t i = 0; i < N/2; ++i){
X[i + N/2] = X[i] - cexp(-2.0*I*M_PI*i/N)*X[i + N/2];
X[i] -= (X[i + N/2]-X[i]);
for (size_t i = 0; i < N / 2; ++i) {
X[i + N/2] = X[i] - cexp(-2.0 * I * M_PI * i / N) * X[i + N / 2];
X[i] -= (X[i + N / 2] - X[i]);
}
}
}

void ifft(double complex *x, size_t n){
for(size_t i = 0; i < n; i++){
void ifft(double complex *x, size_t n) {
for (size_t i = 0; i < n; ++i) {
x[i] = conj(x[i]);
}

fft(x, n);

for(size_t i = 0; i < n; i++){
x[i] = conj(x[i])/n;
for (size_t i = 0; i < n; ++i) {
x[i] = conj(x[i]) / n;
}
}

// This section is a part of the algorithm

void conv(double complex *signal1, double complex *signal2, double complex* out, size_t n1, size_t n2){
void conv(double complex *signal1, double complex *signal2, double complex* out,
size_t n1, size_t n2) {
double complex sum = 0;

for(size_t i = 0; i < (n1 < n2? n2 : n1); i++){
for(size_t j = 0; j < i; j++){
if(j < n1){
for (size_t i = 0; i < (n1 < n2? n2 : n1); ++i) {
for (size_t j = 0; j < i; ++j) {
if (j < n1) {
sum += signal1[j] * signal2[i-j];
}
}
Expand All @@ -57,22 +56,24 @@ void conv(double complex *signal1, double complex *signal2, double complex* out,
}
}

void conv_fft(double complex *signal1, double complex *signal2, double complex* out, size_t n){
void conv_fft(double complex *signal1, double complex *signal2,
double complex* out, size_t n) {
fft(signal1, n);
fft(signal2, n);

for(size_t i = 0; i < n; i++){
out[i] = signal1[i]*signal2[i];
for (size_t i = 0; i < n; ++i) {
out[i] = signal1[i] * signal2[i];
}

ifft(out, n);
}

int main(){
double complex signal1[64], signal2[64], signal3[128], signal4[128], out1[128], out2[128];
int main() {
double complex signal1[64], signal2[64], signal3[128], signal4[128],
out1[128], out2[128];

for(size_t i = 0; i < 128; i++){
if(i >= 16 && i < 48){
for (size_t i = 0; i < 128; ++i) {
if (i >= 16 && i < 48) {
signal1[i] = 1.0;
signal2[i] = 1.0;
signal3[i] = 1.0;
Expand All @@ -97,8 +98,9 @@ int main(){
conv(signal1, signal2, out1, 64, 64);
conv_fft(signal3, signal4, out2, 128);

for(size_t i = 0; i < 64; i++){
printf("%zu %f %+fi\n", i, creal(out1[i]) - creal(out2[i]), cimag(out1[i]) - cimag(out2[i]));
for (size_t i = 0; i < 64; ++i) {
printf("%zu %f %+fi\n", i, creal(out1[i]) - creal(out2[i]),
cimag(out1[i]) - cimag(out2[i]));
}

return 0;
Expand Down
Loading