1

I have a program which reads floating point numbers from a .txt file and puts them into an array but I have a problem with calculating median. Everything is working perfectly except from this. What am I doing wrong?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>


int compare (const void * a, const void * b)
{
  float fa = *(float*) a;
  float fb = *(float*) b;
  return (fa > fb) - (fa < fb);
}



//median calculations//
float median1(float[],int); 
float median1(float array[],int n) 
{  
qsort(array, n, sizeof(float), compare);

if(n%2==0)  
    return (array[n/2]+array[n/2-1])/2;  
else  
    return array[n/2];  
}



float x,l=~(257<<23),a,s,t,median;
main(int n,char**f)

{
char fname[20];
int i;
a=-l;

printf("Please type the file name with an extension (.txt)\n");
scanf("%s", fname);


f=fopen(fname,"r");
for(n=0;fscanf(f,"%f",&x)>0;n++,s+=x,x<l?l=x:0,x>a?a=x:0,t+=x*x);

float array[n];

fseek (f, 0, SEEK_SET);

for (i=0; i<n; i++) 
        {
            fscanf (f, "%f", &(array[n]));
        }

median=median1(array,n);  

printf("Sample size = %d\n", n);
printf("Minimum = %f\n", l);
printf("Maximum = %f\n", a);
printf("Mean = %f\n", s/n);
printf("Median = %f\n",median);
printf("Standard deviation = %f\n", sqrtf(t/n));

return 0;
} 
9
  • Could you describe what's not working. Is it giving the wrong value? Try to step through it with a debugger. Commented Jan 26, 2014 at 2:17
  • @Nabla what do you mean twice? Commented Jan 26, 2014 at 2:19
  • 3
    Why would you have a collection of global variables like x, l, etc? Make them local. I'm puzzled about the initializer for l — quite honestly, I've no idea what it's supposed to do with bit operations on an integer assigned to a float. You'd also lose any marks I was giving out for the line for(n=0;fscanf(f,"%f",&x)>0;n++,s+=x,x<l?l=x:0,x>a?a=x:0,t+=x*x);. That is diabolical — ridiculous — code. Commented Jan 26, 2014 at 2:20
  • This is the highest possible float value. Commented Jan 26, 2014 at 2:32
  • 1
    @xLokos It's high enough so long as no one tries to input something higher. Commented Jan 26, 2014 at 2:41

2 Answers 2

4
fscanf (f, "%f", &(array[n]));

should be

fscanf (f, "%f", &(array[i]));

You are only writing to one array element and that one is out-of-bound.

Even if this wouldn't result in undefined behavior, you would still work with garbage values later on.

See @JonathanLeffler's comment for some further remarks on your code.

Sign up to request clarification or add additional context in comments.

13 Comments

The first read counts how many values there are. This is used to allocate the VLA float array[n]; of the correct size.
@JonathanLeffler Ah ok, I was confused because n is for some reason the first parameter to main.
You're excused for being confused; I hadn't even noticed that. Gruesome doesn't really begin to describe some of the coding feats in here. Notice that f is the other argument to main(int n, char **f), but is also used as a FILE * in f = fopen(fname, "r"); — there's a serious case of not paying attention to compiler warnings here!
@xLokos You don't use them, so either remove them (int main(void)) or give them the usual names argc and argv. Also they are typically not written to. stackoverflow.com/questions/9356510/int-main-vs-void-main-in-c
You only get about six sigfigs from a float, so -321.653992 is most likely the closest representable value to -321.654.
|
0

This is a cleaned up version of your code…but select Nabla's answer.

It compiles cleanly with:

gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
    -Wold-style-definition -Werror med.c -o med

It shows that you were not dreadfully far off. I have not fixed the initializer for l. I did ensure that s and t are both zeroed before you start accumulating values in them. The code does not check that fscanf() works on the second pass. I've not fixed it to read from standard input or to take the file name from its arguments, either of which would make it a lot more usable.

Given input data:

1.2
3.5
2.9
4.6

it produces the output:

Sample size = 4
Minimum = 1.200000
Maximum = 4.600000
Mean = 3.050000
Median = 3.200000
Standard deviation = 3.288617

Semi-fixed code

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int compare(const void *a, const void *b);

int compare(const void *a, const void *b)
{
    float fa = *(float *) a;
    float fb = *(float *) b;
    return (fa > fb) - (fa < fb);
}

// median calculations//
float median1(float[], int);

float median1(float array[], int n)
{
    qsort(array, n, sizeof(float), compare);

    if (n % 2 == 0)
        return (array[n / 2] + array[n / 2 - 1]) / 2;
    else
        return array[n / 2];
}

int main(void)
{
    float x;
    float l = ~(257 << 23);
    float a;
    float s = 0.0;
    float t = 0.0;
    float median;
    int n;
    FILE *f;
    char fname[20];
    int i;
    a = -l;

    printf("Please type the file name with an extension (.txt)\n");
    scanf("%s", fname);


    f = fopen(fname, "r");
    if (f == 0)
    {
        fprintf(stderr, "Failed to open file %s for reading\n", fname);
        return 1;
    }

    for (n = 0; fscanf(f, "%f", &x) > 0; n++)
    {
        s += x;
        if (x<l) l = x;
        if (x>a) a = x;
        t += x * x;
    }

    float array[n];

    fseek(f, 0, SEEK_SET);

    for (i = 0; i < n; i++)
    {
        fscanf(f, "%f", &(array[i]));
    }

    fclose(f);

    median = median1(array, n);

    printf("Sample size = %d\n", n);
    printf("Minimum = %f\n", l);
    printf("Maximum = %f\n", a);
    printf("Mean = %f\n", s / n);
    printf("Median = %f\n", median);
    printf("Standard deviation = %f\n", sqrtf(t / n));

    return 0;
}

8 Comments

I can't say it doesn't look much neater. But still even with this code and input 123.456 999.999 564.312 -654.321 7894.32 it produces output Sample size = 5 Minimum = -654.320984 Maximum = 7894.319824 Mean = 1785.553101 Median = 564.312012 Standard deviation = 3580.003174
That's what I get too from your data: Sample size = 5 Minimum = -654.320984 Maximum = 7894.319824 Mean = 1785.553101 Median = 564.312012 Standard deviation = 3580.003174. It's reasonable given the inputs. Trying to get 10 significant digits from a value that can only hold 6-7 is an exercise in futility, but the default precision for %f is 6 decimal places, so that's what gets printed.
So do you think this whole code will be accepted by my tutor?
I just checked with my GCC and the stdev is slightly different from this in output. My Casio shows sample stdev = 3469.18976
Btw thatnks for your help and time, I appreciate it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.