Cooley-Tukey FFT algorithm & Portaudio - c

I implemented the aforementioned algorithm (https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm).
Here' s the full working code.
I receive streaming input from microphone in a non interleaved stereo Callback.
Then i fill a buffer with input samples and process this buffer into fft and ifft
functions.
Finally i use a pointer to send the processed buffer to output.
I use Asio4all V2.
I really can' t understand where is the problem because it does work properly but i can' t go beyound N=16 or the output sounds highly intermittent.
Thanks a lot in advance.
Callback + Main:
#include <stdio.h>
#include <stdlib.h>
#include "portaudio.h"
#include "FFT.h"
#define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER (64)
#define NUM_SECONDS (10)
typedef struct
{
}
paTestData;
static int patestCallback( void *INbuffers[2], void *OUTbuffers[2],
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
paTestData *data = (paTestData*)userData;
float *inL = (float *) INbuffers [0];
float *inR = (float *) INbuffers [1];
float *outL = (float *) OUTbuffers[0];
float *outR = (float *) OUTbuffers[1];
unsigned long i;
(void) timeInfo;
(void) statusFlags;
for( i=0; i<framesPerBuffer; i++ )
{
for(int i=0; i<N; i++)
{
Y[i] = *inL + 0*I;
}
*inL++;
fft(Y, N);
ifft(Y, N);
for(int i=0; i<N; i++)
{
p_out=&Y[i];
}
*outL++ = *p_out++;
*outR++ = *p_out++;
}
return paContinue;
}
int main()
{
PaStreamParameters inputParameters;
PaStreamParameters outputParameters;
PaStream *stream;
paTestData data;
Pa_Initialize();
inputParameters.device = Pa_GetDefaultInputDevice();
inputParameters.channelCount = 2;
inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
inputParameters.suggestedLatency = 0;
inputParameters.hostApiSpecificStreamInfo = NULL;
outputParameters.device = Pa_GetDefaultOutputDevice();
outputParameters.channelCount = 2;
outputParameters.sampleFormat = paFloat32 | paNonInterleaved;
outputParameters.suggestedLatency = 0;
outputParameters.hostApiSpecificStreamInfo = NULL;
Pa_OpenStream( &stream,
&inputParameters,
&outputParameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paClipOff,
patestCallback,
&data );
Pa_StartStream( stream );
Pa_Sleep( NUM_SECONDS * 1000);
Pa_StopStream( stream );
Pa_CloseStream( stream );
}
Header:
#ifndef FFT_H_INCLUDED
#define FFT_H_INCLUDED
#include <stdio.h>
#include <math.h>
#include <complex.h>
#define N (16)
complex Y[N];
complex *p_out;
void separate (complex *a, int n)
{
complex b[N/2];
for(int i=0; i<n/2; i++) // copy all odd elements to b
b[i] = a[i*2+1];
for(int i=0; i<n/2; i++) // copy all even elements to lower-half of a[]
a[i] = a[i*2];
for(int i=0; i<n/2; i++) // copy all odd (from heap) to upper-half of a[]
a[i+n/2] = b[i];
}
complex fft(complex *X, int m) // forward fft
{
if(m < 2) {
// bottom of recursion.
// Do nothing here, because already X[0] = x[0]
} else {
separate(X, m); // all evens to lower half, all odds to upper half
fft(X, m/2); // recurse even items
fft(X+m/2, m/2); // recurse odd items
for(int k=0; k<m/2; k++) // combine results of two half recursions
{
complex e = X[k ]; // even
complex o = X[k+m/2]; // odd
complex w = cexp( 0 + (-2.*M_PI*k/m)*I ); // w is the twiddle-factor
X[k ] = e + w * o;
X[k+m/2] = e - w * o;
}
}
}
float ifft(complex *X, int m) // inverse fft
{
for (int i=0; i<m; i++)
{
X[i]=conj(X[i]); // conjugate the complex array
}
fft(X, m); // forward fft
for (int i=0; i<m; i++)
{
X[i]=conj(X[i]); // conjugate the complex array again
}
for (int i=0; i<m; i++)
{
X[i] /= m; // scale the numbers
}
}
#endif // FFT_H_INCLUDED

Related

FFT returns NaN values

I'm trying to use the FFTW for my large project, so I wrote a basic program to check if the FFT is working or not. I am trying to send sine values to the FFT and back. After using the FFT forwards and FFT backwards I get exactly the same results, but I get a NaN value at the first element of the array. I read in some of the questions here that the issue is the data type, I need to use long double and fftwl to maintain accuracy of the results.
Where is the problem? Is it in the data type and how can I solve it?
#include <fftw3.h>
#include <math.h>
#include <stdio.h>
#include <complex.h>
#include <stdlib.h>
#include <inttypes.h>
#include <assert.h>
int Ypt=128;
long double PI=3.14159265358979323846;
void complex2FFT( complex long double *U)
{
long double normalizing_factor= 2.0/Ypt;
fftwl_plan plan_f;
fftwl_complex *in;
fftwl_complex *out;
in = (fftwl_complex *) fftwl_malloc(sizeof(fftwl_complex) * Ypt);
out = (fftwl_complex *) fftwl_malloc(sizeof(fftwl_complex) * Ypt);
for (int i = 0; i < Ypt; ++i){
in[i ][0]= creal(U[i]);
in[i ][1]= cimag(U[i]);
}
plan_f = fftwl_plan_dft_1d(Ypt, in, out, FFTW_FORWARD , FFTW_ESTIMATE);
fftwl_execute(plan_f);
for (int i = 0; i < Ypt; ++i){
U[i] = normalizing_factor*out[i][0] + normalizing_factor*out[i][1]*I;
}
fftwl_destroy_plan(plan_f);
fftwl_free(in);
fftwl_free(out);
fftwl_cleanup();
}
void FFT2complex( complex long double *U)
{
long double normalizing_factor= 1.0;
fftwl_plan plan_b;
fftwl_complex *in;
fftwl_complex *out;
in = (fftwl_complex *) fftwl_malloc(sizeof(fftwl_complex) * Ypt);
out = (fftwl_complex *) fftwl_malloc(sizeof(fftwl_complex) * Ypt);
for (int i = 0; i < Ypt; ++i){
out[i ][0]= creal(U[i]);
out[i ][1]= cimag(U[i]);
}
plan_b = fftwl_plan_dft_1d(Ypt, in, out, FFTW_BACKWARD, FFTW_ESTIMATE);
for (int i = 0; i < Ypt; ++i){
U[i] = normalizing_factor*in[i ][0] + normalizing_factor*in[i ][1]*I;
}
fftwl_execute(plan_b);
fftwl_destroy_plan(plan_b);
fftwl_free(in);
fftwl_free(out);
fftwl_cleanup();
}
int main(int argc, char **argv){
long double dy=( (long double)1) / ( (long double)Ypt);
complex long double *U = malloc(Ypt * sizeof(*U));
complex long double *V = malloc(Ypt * sizeof(*V));
for (int i = 0; i < Ypt; ++i){
U[i] = sin( (double) (2.0*PI* (double)i * dy)) ;
V[i] = sin( (double) (2.0*PI* (double)i * dy)) ;
}
char name[45];
FILE *stream;
sprintf(name, "V%d.txt", 0);
stream= fopen(name,"w");
for (int i = 0; i < Ypt; ++i){
fprintf(stream, "%Lf %2.5f %2.5f \n", (long double)i*dy,creal(U[i]),cimag(U[i]));
}
complex2FFT(U);
FFT2complex(U);
for (int i = 0; i < Ypt; ++i){
fprintf(stream, "%Lf %2.5f %2.5f \n", (long double)i*dy,creal(U[i]),cimag(U[i]) );
}
free(U);
free(V);
}
As noticed by #Dietrich Epp , fftwl_execute(plan_b) runs after the output is copied, therefore the output is left unchanged. In addition, FFTW_BACKWARD performs the backward DFT, but it does not mean that the argument in is used as output. Even with flag FFTW_BACKWARD, the input argument of fftw_plan_dft_1d() is in and the output is out.
See for instance that example of forward then backward transform : FFTW forward and back ward yield in different results why?
for (int i = 0; i < Ypt; ++i){
out[i ][0]= creal(U[i]);
out[i ][1]= cimag(U[i]);
}
plan_b = fftwl_plan_dft_1d(Ypt, out, in, FFTW_BACKWARD, FFTW_ESTIMATE);
fftwl_execute(plan_b);
for (int i = 0; i < Ypt; ++i){
U[i] = normalizing_factor*in[i ][0] + normalizing_factor*in[i ][1]*I;
}

Ray tracer not giving different light intensities based on direction

Goal: I am trying to create a ray tracer in C. I just added in a light source that should give each of my three spheres a shading effect based on where the light is. If the light is to the left of all of them, a shadow should be cased on the right.
Problem: When changing the light intensities and position of the light, all the spheres are changed uniformly. The spheres will be more or less lit equally and there is no variation of lighting on individual pixels on the sphere.
My debugging attempts: I have tried looking through the variable outputs by printing out a lot of different info and I think the source comes from my variable
diffuse_light_intensity
which does not change much (through all the iterations on the screen the value changes twice when it should be changing quite often due to the angles of the light on the surface changing quite a bit)
My Code: (my theory is the problem lies in scene_intersect() or cast_ray())
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <limits.h>
typedef struct {
float position[3];
float intensity;
} Light;
typedef struct {
float diffuse_color[3];
} Material;
typedef struct {
float center[3];
float radius;
Material material;
} Sphere;
int arrSub(const float arr1[], const float arr2[], float subArr[], int length) {
/*
Requires 3 equally sized arrays (denoted as length),
arr1 - arr2 will result in the third array subArr
*/
for (int i = 0; i < length; i++) {
subArr[i] = arr1[i] - arr2[i];
}
return 0;
}
int arrAdd(const float arr1[], const float arr2[], float addArr[], int length) {
/*
Requires 3 equally sized arrays (denoted as length),
arr1 + arr2 will result in the third array subArr
*/
for (int i = 0; i < length; i++) {
addArr[i] = arr1[i] + arr2[i];
}
return 0;
}
int arrScalarMult(const float arr1[], float scalar, float newArr[], int length) {
/*
Requires 3 equally sized arrays (denoted as length),
arr1 - arr2 will result in the third array subArr
*/
for (int i = 0; i < length; i++) {
newArr[i] = arr1[i] * scalar;
}
return 0;
}
float dotProduct(const float arr1[], const float arr2[], int length) {
/*
Returns the dot product of two equal sized arrays
(treated as vectors)
a (dot) b = a1b1 + a2b2 + ... anbn
*/
float result = 0;
for (int i = 0; i < length; i++) {
result += arr1[i] * arr2[i];
}
return result;
}
int normalize(float arr[], int len) {
//Normalize a vector (array)
float sumSqr;
float norm;
for (int i = 0; i < len; i++) {
sumSqr += arr[i] * arr[i];
}
norm = sqrt(sumSqr);
for (int i = 0; i < len; i++) {
arr[i] = arr[i] / norm;
}
return 0;
}
bool ray_intersect(const float origin[], const float dir[], float t0, Sphere s) {
/*
Ray-Sphere Intersection
Vectors:
origin (the zero vector)
dir (direction vector)
L (vector from origin to center of sphere)
Scalars:
tca
d2
thc
t0
t1
*/
float L[3] = {0,0,0}; //The zero vector
arrSub(s.center, origin, L, 3); //L is now the vector from origin to the sphere's center
float tca = dotProduct(L, dir, 3); //Projection of L onto dir
float d2 = dotProduct(L, L, 3) - tca*tca;
if (d2 > s.radius * s.radius) return false; //There is no intersection, so return false.
float thc = sqrtf((s.radius*s.radius - d2));
t0 = tca - thc;
float t1 = tca + thc;
if (t0 < 0) {
t0 = t1;
}
if (t0 < 0) return false;
return true;
}
bool scene_intersect(const float origin[], const float dir[], const Sphere s[], int len, float hit[], float N[], Material * ptr_m) {
float sphere_dist = INT_MAX;
for (size_t i=0; i < len; i++) {
float dist_i;
if (ray_intersect(origin, dir, dist_i, s[i]) && dist_i < sphere_dist) {
sphere_dist = dist_i;
float dirDist[3];
arrScalarMult(dir, dist_i, dirDist, 3);
arrAdd(origin, dirDist, hit, 3);
float hitMinusCenter[3];
arrSub(hit, s[i].center, hitMinusCenter, 3);
normalize(hitMinusCenter, 3);
N[0] = hitMinusCenter[0];
N[1] = hitMinusCenter[1];
N[2] = hitMinusCenter[2];
* ptr_m = s[i].material;
}
}
return sphere_dist<1000;
}
int cast_ray(const float origin[], const float dir[], const Sphere s[], const Light l[], int l_size, unsigned char colorArr[]) {
float point[3], N[3];
Material m;
Material * ptr_m = &m;
if (!scene_intersect(origin, dir, s, 3, point, N, ptr_m)) {
//background
colorArr[0] = 5; //red
colorArr[1] = 100; //green
colorArr[2] = 250; //blue
} else {
float diffuse_light_intensity = 0;
float light_dir[3];
for (size_t i = 0; i < l_size; i++) {
arrSub(l[i].position, point, light_dir, 3);
normalize(light_dir, 3);
diffuse_light_intensity += l[i].intensity * ((0.f >= dotProduct(light_dir, N, 3) ? (0.f) : (dotProduct(light_dir, N, 3))));
}
//light up pixel
colorArr[0] = m.diffuse_color[0] * diffuse_light_intensity;
colorArr[1] = m.diffuse_color[1] * diffuse_light_intensity;
colorArr[2] = m.diffuse_color[2] * diffuse_light_intensity;
}
return 0;
}
int render(const Sphere s[], const Light l[], int l_length) {
/*
Creates image in a new color each step.
*/
const int width = 1024;
const int height = 768;
FILE *fp = fopen("fourth.ppm", "wb"); // Write in binary mode
(void) fprintf(fp, "P6\n%d %d\n255\n", width, height);
float fov = 3.1415926535/2.; // Field of View
#pragma omp parallel for
for (size_t j = 0; j < height; j++) {
for (size_t i = 0; i < width; i++) {
float x = (2*(i+.5)/(float)width - 1)*tan(fov/2.)*width/(float)height;
float y = -(2*(j+.5)/(float)height - 1)*tan(fov/2.);
float dir[] = {x,y,-1};
normalize(dir, 3);
unsigned char color[3];
const float origin[] = {0,0,0};
cast_ray(origin, dir, s, l, l_length, color);
(void) fwrite(color, 1, 3, fp);
}
}
(void) fclose(fp);
return 0;
}
int main(void) {
Material red = {255,0,0};
Material pink = {150,10,150};
Material gold = {255, 195, 0};
//Populate with spheres
Sphere s[3];
Sphere originalS = {{-3,0,-16},2,gold};
Sphere bigS = {{-1.0, -1.5, -12}, 3, red};
Sphere anotherS = {{7,5,-18},2,pink};
s[0] = originalS;
s[1] = bigS;
s[2] = anotherS;
//Add light source
Light l[1];
Light test_light = {{-20,20,20}, 1.5};
l[0] = test_light;
render(s,l, 1);
printf("Run success!\n");
return 0;
}
If any clarification is needed on my code please let me know, I am quite new to both C and stackoverflow.
There's a fundamental error in ray_intersect where you're passing the t0 variable by value, and not as a pointer, and therefore in the scene_intersect function its value is always zero.
The other problem is that you don't initialize the sumSqr in the normalize function, resulting in that function returning NaN for each vector component.
With those two fixed I get something approximating shaded balls. The errors in that image are caused by failing to ensure that your output pixel values fall in the range [0, 255].
NB: both of these first errors are detected if you turn on full compiler error checking, warning you of uninitialised variables being used.

Troubles with implementation of cooley FFT

I am doing a convolution of two integer signals with the help of FFT, but somehow I can't get it right. I am not sure if my implementation of FFT is correct. Especially the math part.
big edit:
I posted all the code now. My apologies for not starting with it. I was sure the error was only in FFT part, but there might be more problems I overlooked. I know the code is messy and not clean. Everything is a bit fragmented and can be programmed in a simpler and cleaner way, but I was testing bit by bit. As for input it reads two signals from the command line. build up as a number indicating how big the signal is and the signal presented as an integer array e.q 2: [1,-1] and 10: [0,0,0,1,1,1,1,0,0,0]. It should then do a convolution on the signals by performing a FFT on both of them then do bit wise multiplication. With a inverse FFT on the resulting signal. Printing it again with the length and then the array consiting of integers. The printing itself is correct, but the values in the resulting array is not correct. I hope it is all a bit clearer now again my apologies and thank you for your help so far.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
double PI;
int *readSignal(int *len) { //reads the signal
int *x;
char c;
scanf("%d:", len);
x = calloc(*len, sizeof(int));
do c = getchar(); while (c != '[');
if (len > 0) {
scanf("%d", &x[0]);
for (int i=1; i < *len; i++) scanf(",%d", &x[i]);
}
do c = getchar(); while (c != ']');
return x;
}
void printSignal(int len, int *x) { //prints the signal
printf("%d: [", len);
if (len > 0) {
printf("%d", x[0]);
for (int i=1; i < len; i++)
printf(",%d", x[i]);
}
printf("]\n");
}
void *padSignal(int len, int lenSig, int *x) { //ensures that the signal is of size 2^n by padding it with 0's
int *padded;
padded = calloc(len, sizeof(int));
for (int i=0; i < lenSig; i++) {
padded[i] = x[i];
}
return padded;
}
void fft(double complex signal[], int length, int power) {
if (length == 1) {
return;
}
double complex *signalODD = calloc((length/2+1), sizeof(double complex));
double complex *signalEVEN = calloc((length/2+1), sizeof(double complex));
int index1 = 0;
int index2 = 0;
for(int i = 0; i < length; i++) {
if(i % 2 ==0) {
signalEVEN[index1] = signal[i];
index1++;
}
else {
signalODD[index2] = signal[i];
index2++;
}
}
fft(signalEVEN,length/2, power+1);
fft(signalODD,length/2, power+1);
for(int i = 0; i<length/2-1; i++) {
signal[i] = signalEVEN[i] + cexp((I*2*PI*i)/length)*signalODD[i];
signal[i+length/2] = signalEVEN[i]-cexp((I*2*PI*i)/length)*signalODD[i];
}
free(signalODD);
free(signalEVEN);
}
void ifft(double complex signal[], int length, int power) {
if (length == 1) {
return;
}
double complex *signalODD = calloc((length/2+1), sizeof(double complex));
double complex *signalEVEN = calloc((length/2+1), sizeof(double complex));
int index1 = 0;
int index2 = 0;
for(int i = 0; i < length; i++) {
if(i % 2 ==0) {
signalEVEN[index1] = signal[i];
index1++;
}
else {
signalODD[index2] = signal[i];
index2++;
}
}
fft(signalEVEN,length/2, power+1);
ifft(signalODD,length/2, power+1);
for(int i = 0; i<length/2-1; i++) {
signal[i] = signalEVEN[i] + cexp((I*-2*PI*i)/length)*signalODD[i];
signal[i+length/2] = signalEVEN[i]-cexp((I*-2*PI*i)/length)*signalODD[i];
}
free(signalODD);
free(signalEVEN);
}
int checkPowerofTwo(double len) { //checks for the closed power of 2
double x = 1;
while(len > pow(2,x)) {
x++;
}
return pow(2,x);
}
int main(int argc, char *argv[]) {
int lenH, *H;
int lenX, *X;
int *paddedX;
int *paddedH;
double length;
H=readSignal(&lenH); //reads in the signal H
X=readSignal(&lenX); //reads in signal X
length = lenH+lenX-1;
paddedH=padSignal((length),lenH,H); //pads the signal to the length
paddedX=padSignal((length),lenX,X); // pads the signal to the length
double complex *signalX = calloc(length, sizeof(double complex)); //creats a complex signal X and fills it with paddedX
for (int i = 0; i<length; i++) {
signalX[i] = paddedX[i];
}
double complex *signalH = calloc(length, sizeof(double complex)); // same for H
for (int i = 0; i<length; i++) {
signalH[i] = paddedH[i];
}
fft(signalX, length, 1); //performs the fast fourier transform on X
fft(signalH,length, 1); // performs the fast fourier transfom on H
double complex *signalY = calloc(length, sizeof(double complex)); //makes complex signal Y
for (int i = 0; i<length; i++) { //performs the convolution
signalY[i] = signalX[i]*signalH[i];
}
ifft(signalY, length,1);
int *output = calloc(length, sizeof(int)); //creates the final output signal
for (int i = 0; i<length; i++) {
output[i] = creal(signalY[i]);
}
printSignal(length,output);
free(signalX);
free(signalH);
free(signalY);
free(H);
free(X);
free(paddedH);
free(paddedX);
free(output);
return 0;
}
In:
if(i % 2 ==0 && i != 0)
Why do you exclude i == 0? Change that to if(i % 2 ==0) in both fft and ifft.
In both fft and ifft, the line:
for(int i = 0; i<lenght/2-1; i++) {
should be:
for(int i = 0; i<lenght/2; i++) {
In ifft, the recursion accidentally uses fft:
fft(signalEVEN,lenght/2, power+1);
fft(signalODD,lenght/2, power+1);
Change those to ifft.
The calloc calls do not need this much space:
calloc((lenght/2 + 1), sizeof(double complex));
That can be:
calloc((lenght/2), sizeof(double complex));
Also, the proper spelling of is “length”.
With those fixed, the fft and ifft routines appear to work for some superficial cases.

How do I find distance between couple of points (x, y) from origin, and then sort the points, who is closest to (0, 0)?

i need to enter number of points(x,y), and then sort the points,from the closest one to (0,0) to the one that is far.. for example:
Enter number of points: 3
Enter point: 1 6
Enter point: 2 5
Enter point: 4 4
Sorted points:(2,5) (4,4) (1,6)
now i did a function that will find the distance,and i did an array and put the distance between two coordinate x and y,and i want to use merge sort to sort the array, my problem is how to go back and print the actual coordinate x y ... (i hope you would understand the problem),what can i do? i thought of putting the cordinate an array and sort them but that won't work :\
(and i didn't learn struct so i can't use unless if there is no other way ...)
plz anyone can help me i really have no idea have to continue:\
#include <stdio.h>
#include <stdlib.h>
void Enter_numbers(int x,int *z,int *first_coordinate,int *second_coordinate);
int distance(int a,int b);
void merge(int a[], int na, int b[], int nb, int c[]);
int merge_sort(int ar[], int n);
int main()
{
int x;
int *z;
int *first_coordinate;
int *second_coordinate;
printf("Enter number of points: ");
scanf("%d",&x);
z=(int*)malloc(x*sizeof(int));
first_coordinate=(int*)malloc(x*sizeof(int));
second_coordinate=(int*)malloc(x*sizeof(int));
Enter_numbers(x,z,first_coordinate,second_coordinate);
free(z);
free(first_coordinate);
free(second_coordinate);
return 0;
}
int distance(int a,int b)
{
int dis;
dis=((a*a)+(b*b));
return dis;
}
void Enter_numbers(int x,int *z,int *first_coordinate,int *second_coordinate)
{
int a=0,b=0;
int i=0;
int diss=0;
while(x>0)
{
printf("Enter points: ");
scanf("%d %d",&a,&b);
diss=distance(a,b);
z[i]=diss;
first_coordinate[i]=a;
second_coordinate[i]=b;
++i;
x--;
}
}
and the merge sort function i will use after i figure what to do :
int merge_sort(int ar[], int n)
{
int len;
int *temp_array, *base;
temp_array = (int*)malloc(sizeof(int)*n);
if(temp_array == NULL) {
printf("Dynamic Allocation Error in merge_sort");
return FAILURE;
}
for (len = 1; len < n; len *= 2) {
for (base = ar; base < ar + n; base += 2 * len) {
merge(base, len, base + len, len, temp_array);
memcpy(base, temp_array, 2*len*sizeof(int));
}
}
free(temp_array);
return SUCCESS;
}
and here is merge ...
void merge(int a[], int na, int b[], int nb, int c[])
{
int ia, ib, ic;
for(ia = ib = ic = 0; (ia < na) && (ib < nb); ic++)
{
if(a[ia] < b[ib]) {
c[ic] = a[ia];
ia++;
}
else {
c[ic] = b[ib];
ib++;
}
}
for(;ia < na; ia++, ic++) c[ic] = a[ia];
for(;ib < nb; ib++, ic++) c[ic] = b[ib];
}
I would use a struct for solving this task.
If you haven't learned struct yet, this seems to be a good time to learn it.
Note: If you really can't use stuct, see the last part of the answer.
With struct it could be something like:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int x;
int y;
int squared_distance;
} dpoint;
int squared_dst(int x, int y)
{
return (x*x + y*y);
}
// Compare function used for sorting
int compare_dpoint_dst(const void * e1, const void * e2)
{
dpoint* p1 = (dpoint*)e1;
dpoint* p2 = (dpoint*)e2;
if (p1->squared_distance > p2->squared_distance) return 1;
if (p1->squared_distance < p2->squared_distance) return -1;
return 0;
}
void print_dpoint(dpoint dp)
{
printf("(%d, %d) : sd = %d\n", dp.x, dp.y, dp.squared_distance);
}
#define N 5
int main(void) {
// Array of points (fixed size for simplicity)
dpoint ps[N];
// Dummy input (for simplicity)
int x[N] = {1,5,2,3,4};
int y[N] = {9,3,7,1,3};
for (int i = 0; i < N; ++i)
{
ps[i].x = x[i];
ps[i].y = y[i];
}
// Calculate squared distance for all points
for (int i = 0; i < N; ++i)
{
ps[i].squared_distance = squared_dst(ps[i].x, ps[i].y);
}
printf("unsorted:\n");
for (int i = 0; i < N; ++i)
{
print_dpoint(ps[i]);
}
// Sort the points
qsort (ps, sizeof(ps)/sizeof(*ps), sizeof(*ps), compare_dpoint_dst);
printf("sorted:\n");
for (int i = 0; i < N; ++i)
{
print_dpoint(ps[i]);
}
return 0;
}
Notice that you can do the sorting on the squared distance so that you don't need square root in the program.
The program above will generate:
unsorted:
(1, 9) : sd = 82
(5, 3) : sd = 34
(2, 7) : sd = 53
(3, 1) : sd = 10
(4, 3) : sd = 25
sorted:
(3, 1) : sd = 10
(4, 3) : sd = 25
(5, 3) : sd = 34
(2, 7) : sd = 53
(1, 9) : sd = 82
No use of struct
If you for some reason can't use struct, you can use a shadow array to track the sorting but you'll have to write your own sorting. I don't recommend this approach - learn about structinstead. Anyway, it could be something like:
int x[N];
int y[N];
int sd[N]; // squared distance
int sw[N]; // swap order
// read input and calculate distance
// ...
// Fill sw with 0, 1, 2, ....
for (int i=0; i < N; ++i) sw[i] = i;
mySort(sd, sw, N);
// Now you can use sw for printing
for (int i=0; i < N; ++i)
{
// print element sw[i]
printf("(%d,%d)\n", x[sw[i]], y[sw[i]]);
}
}
void mySort(int sd[], int sw[], int N)
{
// .... code for sorting
// ....
// Assume that you need to swap element i and j here
temp = sd[i];
sd[i] = sd[j];
sd[j] = temp;
// Then do exactly the same for sw
temp = sw[i];
sw[i] = sw[j];
sw[j] = temp;
// ....
// ....
}

Compiler error after increasing size of automatic arrays in C

I am trying to calculate a correlation measure for 18456 genes but the compiler (Dev C) exits after increasing macros GENE or INDEX to a value between 4000 and 5000 or bigger. For example it works well with:
# define GENE 4000
# define INDEX 3000
but not with:
#define GENE 5000
#define INDEX 100
The input file is a space delimited text file with 18456 rows and 57 columns.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <limits.h>
#define GENE 5000
#define N 57
#define INDEX 1000
int main (void) {
clock_t start, stop;
double t = 0.0;
int i, j, p, q, wp, wq;
double x;
double *S_matrix = (double *)malloc(INDEX * GENE * sizeof(double));
double sum_S, S_max;
double S[11] = {0};
double r = 0.0, xbar = 0.0, ybar = 0.0, sx = 0.0, sy = 0.0;
// read E matrix
FILE *fq;
double E[GENE][N] = {{0}};
if ((fq = fopen("E_disease.txt", "r")) == NULL )
{
printf("Error\n");
exit(EXIT_FAILURE);
}
fq = fopen("E_disease.txt","r");
printf("\n");
for (i=0;i<GENE;i++)
{
for(j=0;j<N;j++)
{
fscanf(fq,"%lf",&x);
E[i][j] = x;
}
}
printf("\n");
fclose(fq);
// calculate correlation
assert((start = clock())!=-1);
for(p=0; p < INDEX; p++)
{
for(q=0; q < GENE; q++)
{
for(i=0; i<11; i++)
{
/*compute xbar */
for(j = i; j < N; j++)
{
xbar += E[p][j];
}
xbar /= N;
/*compute ybar*/
for(j = i; j < N; j++)
{
ybar += E[q][j];
}
ybar /= N;
/* compute standard deviation of x*/
for(j = i; j < N; j++)
{
sx += (E[p][j] - xbar) * (E[p][j] - xbar);
}
sx = sqrt(sx);
/* compute standard deviation of y */
for(j = i; j < N; j++)
{
sy += (E[q][j] - ybar) * (E[q][j] - ybar);
}
sy = sqrt(sy);
/*compute r, the correlation coefficient between the two arrays */
for( j = i; j < N; j++ )
{
r += (((E[p][j] - xbar)/sx) * ((E[q][j] - ybar)/sy));
}
r /= (N);
if(r>0)
{
S[i] = r;
}
else if(r<=0)
{
S[i] = 0;
}
}
for(j=0, sum_S=0; j<11; j++)
{
sum_S += S[j];
}
for(j=0, S_max = 0; j<11; j++)
{
if(S[j] > S_max)
{
S_max = S[j];
}
}
S_matrix[p*GENE + q] = sum_S/(11*S_max);
}
}
FILE * fs;
fs = fopen ("s_matrix.txt", "w+");
for(wp=0; wp<INDEX; ++wp)
{
for(wq=0; wq<GENE; ++wq)
{
fprintf(fs, "%lf", S_matrix[wp*GENE + wq]);
fprintf(fs, "\t");
}
fprintf(fs, "\n");
printf("\n");
}
fclose(fs);
stop = clock();
t = (double) (stop-start)/CLOCKS_PER_SEC;
printf("Run time: %f\n", t);
//print results
//return (0);
getchar();
}
Let me simplify the code. When I ran the code below, a couple of times, it generally exited immediately. One time, it said that it could not find something like 0xff12345. Another time it printed out S_matrix[55] when I defined constants inside main (the rest of the code is same) like int GENE=100; but just one time. Is that mean a memory leak? It does not give an error message when I compile it but are defining matrices and assigning values to them true?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <time.h>
#include <limits.h>
#define GENE 100
#define N 57
#define INDEX 10
int main (void) {
//int GENE = 100;
//int N = 57;
//int INDEX = 10;
int i, j;
double x;
double *S_matrix = (double *)malloc(INDEX * GENE * sizeof(double));
double *E = (double*)malloc(GENE*N*sizeof(double));
// read E matrix
FILE *fq;
if ((fq = fopen("E_control.txt", "r")) == NULL )
{
printf("Error\n");
exit(EXIT_FAILURE);
}
fq = fopen("E_control.txt","r");
printf("\n");
for (i=0;i<GENE;i++)
{
for(j=0;j<N;j++)
{
fscanf(fq,"%lf",&x);
E[i*GENE+j] = x;
}
}
printf("\n");
fclose(fq);
for(i=0; i<INDEX; i++)
{
for(j=0; j<GENE; j++)
{
S_matrix[i*INDEX+j]=i*j;
}
}
printf("%f " , S_matrix[55]);
free(S_matrix);
S_matrix=NULL;
free(E);
E=NULL;
return(0);
getchar();
getchar();
}
You're attempting to reserve 2280000 bytes of stack space (actually more) in main() because of a overtly large fixed array declaration. Specifically, this line:
double E[GENE][N] = {{0}};
equates to
double E[5000][57] = {{0}};
At 8-bytes per double, thats highly likely to be blowing out your stack. Use dynamic allocation for that array instead. For example:
double (*E)[N] = malloc(5000*sizeof(*E));
And don't forget to free it when you're done.
Global fixed allocation will also work (i.e. declare it as a global outside the main() function block.
static double E[GENE][N];
int main()
{
... your code ...
}
Any method you choose has potential advantages and pitfalls, so plan accordingly.

Resources