Andy Pallermo
Andy Pallermo

Reputation: 7

Program to find Heat Index and Wind Chill (C Program)

I am having some trouble with the output of my program and can't figure out where I am going wrong. The Temperatures seem to be converting from celsius to Fahrenheit correctly, but when it comes to the the wind chill and heat index values, they are incorrect. This makes me think that something is wrong with the way I'm calculating them in my functions? If I could get an explanation to where my logic is wrong that would be great. Thanks in advance and sorry for my poor formatting!

#include <stdio.h>
#include <math.h>
#define L_Limit -20
#define U_Limit 50
#define c1 -42.379
#define c2 2.04901523
#define c3 10.14333127
#define c4 -0.22475541
#define c5 -6.83783E-3
#define c6 -5.481717E-2
#define c7 1.22874E-3
#define c8 8.5282E-4
#define c9 -1.99E-6
#define d1 35.74
#define d2 0.6125
#define d3 35.75
#define d4 0.4275

double compute_heat_index(int num1, int num2);
double compute_wind_chill(int num1, int num2);

double compute_heat_index(int num1, int num2)
{
    int celsius;
    double humid=.40;
    double celsius_f=0, heat_index=0;
    int ext1=0;
    for(celsius=1;celsius<=num2;celsius++)
    {
        printf("%d\t", celsius);
        celsius_f=(celsius*(9/5))+32;
        printf("%2.2lf\t", celsius_f);

        for(humid=.40;humid<=1;humid=humid+.10)
        {
            heat_index=c1+(c2*celsius_f)+(c3*humid)+.   (c4*humid*celsius_f)+(c5*pow(celsius,2))+(c6*pow(humid,2))+(c7*pow(celsius,2)*humid)+(c8*celsius*pow(humid,2))+(c9*pow(celsius,2)*pow(humid,2));
            if(heat_index<80)
                printf("x\t");
            else
                printf("%2.2lf/t", heat_index);
        }
        if(celsius_f>100)
        {
            ext1++;
        }
        humid=.40;
        celsius_f=0;
        heat_index=0;
    }
    return heat_index;
}

double compute_wind_chill(int num1, int num2)
{
    int celsius, wind=5;
    double celsius_f=0, wind_chill=0;
    int ext2=0;
    for(celsius=1;celsius<=num2;celsius++)
    {
        printf("%d\t", celsius);
        celsius_f=(celsius*(9/5))+32;
        printf("%lf\t", celsius_f);

        for(wind=5;wind<=40;wind=wind+5)
        {
            wind_chill=d1+(d2*celsius_f)-(d3*wind)+(d4*celsius_f*wind);
            if(wind_chill>50)
                printf("x\t");
            else 
                printf("%lf\t", wind_chill);
        }
        if(celsius_f<-20)
        {
            ext2++;
        }
        wind=5;
        celsius_f=0;
        wind_chill=0;
    }
    return wind_chill;
}
int main(void)
{
    double num1, num2;
    int ext1=0, ext2=0;

    printf("Input a range of values using two numbers:\n");
    scanf("\n%lf%lf", &num1, &num2);

    while(num1<L_Limit&&num1>U_Limit&&num2<L_Limit&&num2<U_Limit)
    {
        printf("Range of Values are Invalid!\n");
        scanf("\n%lf%lf", &num1, &num2);
    }
  printf("Celsius\tFahrenheit\t5mph\t10mph\t15mph\t20mph\t25mph\t30mph\t35mph\t40mph\n");
    compute_wind_chill(num1, num2);
    printf("\nTotal Extreme Values: %d", ext1);
    compute_heat_index(num1, num2);
    printf("\nTotal Extreme Values: %d", ext2);

    return 0;
}

Upvotes: 0

Views: 1697

Answers (2)

David C. Rankin
David C. Rankin

Reputation: 84551

While I make no comment on the correctness of your stoichiometric calculations (though I provide links and hints at the end), the following will help you find the problem, not only here, but hopefully in all future code you write as well. You are making things harder on yourself than they need be just by how you are formatting your code. Unless you are competing in a contest to see how few lines you can use, then for goodness sake, make things easier on yourself by 'opening up' you code a bit. This will make it much easier for you, and anyone helping you, to follow the logic of your code and find logic errors. For example, it is almost impossible to spot logic errors in:

            heat_index=c1+(c2*celsius_f)+(c3*humid)+.   (c4*humid*celsius_f)+(c5*pow(celsius,2))+(c6*pow(humid,2))+(c7*pow(celsius,2)*humid)+(c8*celsius*pow(humid,2))+(c9*pow(celsius,2)*pow(humid,2));

(of course your compiler will loudly complain about the errouneous '.' at the end of the first line)

It is much more readable written as:

            heat_index = c1 + (c2 * celsius_f) + (c3 * humid) +
                (c4 * humid * celsius_f) + (c5 * pow (celsius, 2)) +
                (c6 * pow (humid, 2)) + (c7 * pow (celsius, 2) * humid) +
                (c8 * celsius * pow (humid, 2)) +
                (c9 * pow (celsius, 2) * pow (humid, 2));

or even:

            heat_index = c1 + 
                        (c2 * celsius_f) + 
                        (c3 * humid) +
                        (c4 * humid * celsius_f) + 
                        (c5 * pow (celsius, 2)) +
                        (c6 * pow (humid, 2)) + 
                        (c7 * pow (celsius, 2) * humid) +
                        (c8 * celsius * pow (humid, 2)) +
                        (c9 * pow (celsius, 2) * pow (humid, 2));

NOTE: above you can easily see the misuse of celsius where celsius_f (Fahrenheit) should be used. Also note there is no need for pow (celsius_f, 2) where celsius_f * celsius_f will do the job.

Do the same for your output. Make it easy for you to read so it will be easier for others to read as well.

(I'm getting old and maybe your young-eyes have no trouble with code without spaces, it is much easier on me to help you if your code is adequately spaced and properly indented and your output looks like something other than spaghetti strung across the screen)

Avoid using 'magic numbers' in your code, e.g.

    for(wind=5;wind<=40;wind=wind+5)

If you need constants in your code, declare them as required. That way, there is only one place you need to change the value, easily found at the top, instead of picking though your code to find them. You have declared a large number for your wet-bulb/dry-blub calculations, a few more for your limits is all that is required, e.g.

#define HMIN .40    /* define needed constants */
#define HMAX 1.0    /* avoid putting 'magic'   */
#define HSTEP 0.1   /* numbers in your code    */

#define WMIN 5
#define WMAX 40
#define WSTEP 5
...
    for (wind = WMIN; wind <= WMAX; wind = wind + WSTEP)

Note: your HMIN, HMAX, HSTEP values will change when you correct your units (see last paragraph).

It appears you are wanting to return the values of ext1 and ext2 from your compute_wind_chill and compute_heat_index functions. If so, then your function type should match your return type needed. If you are wanting to indicate whether a extreme value was encountered by returning ext1 and ext2, then you should change your function type to int and assign the return to ext1 and ext2 in main, e.g.

int compute_heat_index (int num1, int num2);
int compute_wind_chill (int num1, int num2);
...
    ext1 = compute_wind_chill (num1, num2);
    printf ("\nTotal Extreme Values: %d\n", ext1);
    ...
    ext2 = compute_heat_index (num1, num2);
    printf ("\nTotal Extreme Values: %d\n", ext2);

Next, there is no need to make multiple calls to, e.g. printf when one will do. For example:

    printf("%d\t", celsius);
    celsius_f=(celsius*(9/5))+32;
    printf("%2.2lf\t", celsius_f);

can be easily replaced with a single printf call just by logically ordering your celsius_f calculation, e.g.

    celsius_f = (celsius * (9 / 5)) + 32;
    printf ("%d\t% .2lf\t", celsius, celsius_f);

Why you declare num1 and num2 as double in main is a complete mystery. You pass them as int to your functions (where I assume num1 is supposed to be the lower loop value for temp in the functions instead of the hardcoded 1 you have). While you are free to allow users to enter e.g. 45.3 and read it as a double, and pass it as an int, it doesn't really make much logical sense. Here, the value of 45 is all that is ever used on your code. If you are reading as a double just to prevent error if a user enters 45.3, then that is a legitimate reason, but why a user would rather enter 45.3 instead of just 45 is another matter...

Your limit testing for values less/greater than L_Limit/U_Limit is a bit creative. It is better to simply put the values in ascending order to simplify the test, e.g.

    /* VALIDATE all user input */
    if (scanf ("%lf %lf", &num1, &num2) != 2) {
        fprintf (stderr, "error: invalid input.\n");
        return 1;
    }

    if (num1 > num2) {      /* get values in ascending order */
        double tmp = num1;
        num1 = num2;
        num2 = tmp;
    }

    while (num1 < L_Limit || num2 > U_Limit) {  /* simple test */

Formatting your output is just something that takes a little more attention to detail. While I'm no fan of tab ('\t') formatting, I've made a quick attempt to clean things up a little to make the output more legible. Similarly, when you need an additional newline character, do not use the variadic printf ("\n");, there is no reason for the overhead just to output one character, use putchar ('\n'); instead. (note: you don't make that mistake, but I had to add a newline so it was worth mentioning here).

When you compile your code, always compile with warnings enabled, e.g. -Wall -Wextra in your compile string. You can add -pedantic for a few additional checks and there are a multitude of additional individual checks you can impose. Above all, do not accept code until it compiles cleanly, without warnings. Read the warnings you get. The compilers are quite good now at explaining exactly where the problem is and what you are doing wrong. (you can learn a lot of C, just by listening to what your compiler is telling you).

You can compile your code with something similar to the following:

$ gcc -Wall -Wextra -pedantic -std=gnu11 -Ofast -o bin/windchill windchill.c

Finally, putting it altogether, you could reformat your code and incorporate the changes above into something like the following that should make finding your stoichiometric logic error much easier. I have put my additional thoughts in the comments below:

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

#define L_Limit -20
#define U_Limit 50
#define c1 -42.379
#define c2 2.04901523
#define c3 10.14333127
#define c4 -0.22475541
#define c5 -6.83783E-3
#define c6 -5.481717E-2
#define c7 1.22874E-3
#define c8 8.5282E-4
#define c9 -1.99E-6
#define d1 35.74
#define d2 0.6125
#define d3 35.75
#define d4 0.4275

#define HMIN .40    /* define needed constants */
#define HMAX 1.0    /* avoid putting 'magic'   */
#define HSTEP 0.1   /* number in your code     */

#define WMIN 5
#define WMAX 40
#define WSTEP 5

/* you only need prototypes if you do not define your functions
 * until AFTER the code that makes use of them. Moving the 
 * definitions AFTER main() makes the prototypes make sense,
 * otherwise, just omit them...
 */
int compute_heat_index (int num1, int num2);
int compute_wind_chill (int num1, int num2);

int main (void) {

    double num1 = L_Limit - 1.0,  /* num1 & num2 should be int */
           num2 = U_Limit + 1.0;
    int ext1 = 0, ext2 = 0;

    printf ("Input a range of temps in deg. C, (e.g. t1 t2): ");

    /* VALIDATE all user input */
    if (scanf ("%lf %lf", &num1, &num2) != 2) {
        fprintf (stderr, "error: invalid input.\n");
        return 1;
    }

    if (num1 > num2) {      /* get values in ascending order */
        double tmp = num1;
        num1 = num2;
        num2 = tmp;
    }

    while (num1 < L_Limit || num2 > U_Limit) {  /* simple test */
        fprintf (stderr, "error: values must be between %d - %d.\n",
                L_Limit, U_Limit);
        printf ("Input a range of temps in deg. C, (e.g. t1 t2): ");
        if (scanf ("%lf %lf", &num1, &num2) != 2) {
            fprintf (stderr, "error: invalid input.\n");
            return 1;
        }
    }

    /* make the output format easy to read */
    printf ("\nDeg. C\t Deg. F\t 5mph\t 10mph\t 15mph\t"
            " 20mph\t 25mph\t 30mph\t 35mph\t 40mph\n");
    ext1 = compute_wind_chill (num1, num2);
    printf ("\nTotal Extreme Values: %d\n", ext1);

    printf ("\nDeg. C\t Deg. F\t 40%%\t 50%%\t 60%%\t"
            " 70%%\t 80%%\t 90%%\t 100%%\n");
    ext2 = compute_heat_index (num1, num2);
    printf ("\nTotal Extreme Values: %d\n", ext2);

    return 0;
}

/* comput and output heat index between num1 and num2 */
int compute_heat_index (int num1, int num2)
{
    int celsius, ext1 = 0;
    double humid = HMIN, celsius_f = 0, heat_index = 0;

    for (celsius = num1; celsius <= num2; celsius++) 
    {
        celsius_f = (celsius * (9 / 5)) + 32;
        printf ("%d\t% .2lf\t", celsius, celsius_f);

        for (humid = HMIN; humid <= HMAX; humid = humid + HSTEP) 
        {
            heat_index = c1 + (c2 * celsius_f) + (c3 * humid) +
                (c4 * humid * celsius_f) + (c5 * pow (celsius, 2)) +
                (c6 * pow (humid, 2)) + (c7 * pow (celsius, 2) * humid) +
                (c8 * celsius * pow (humid, 2)) +
                (c9 * pow (celsius, 2) * pow (humid, 2));

            if (heat_index < 80)
                printf ("x\t");
            else
                printf ("% .2lf\t", heat_index);
        }
        putchar ('\n');

        if (celsius_f > 100) {
            ext1++;
        }
    }

    return ext1;
}

/* comput and output wind chill between num1 and num2 */
int compute_wind_chill (int num1, int num2)
{
    int celsius, wind = WMIN, ext2 = 0;
    double celsius_f = 0, wind_chill = 0;

    for (celsius = num1; celsius <= num2; celsius++) 
    {
        celsius_f = (celsius * (9 / 5)) + 32;
        printf ("%d\t% .2lf\t", celsius, celsius_f);

        for (wind = WMIN; wind <= WMAX; wind = wind + WSTEP) 
        {
            wind_chill = d1 + (d2 * celsius_f) - (d3 * wind) + 
                        (d4 * celsius_f * wind);

            if (wind_chill > 50)
                printf (" x\t");
            else
                printf ("% .2lf\t", wind_chill);
        }
        putchar ('\n');

        if (celsius_f < -20) {
            ext2++;
        }
    }

    return ext2;
}

Example Use/Output

$ ./bin/windchill
Input a range of temps in deg. C, (e.g. t1 t2): 45 55
error: values must be between -20 - 50.
Input a range of temps in deg. C, (e.g. t1 t2): 45 50

Deg. C   Deg. F  5mph    10mph   15mph   20mph   25mph   30mph   35mph   40mph
45       77.00   x       x       40.41   26.25   12.09  -2.07   -16.23  -30.40
46       78.00   x       x       47.44   35.42   23.39   11.37  -0.66   -12.68
47       79.00   x       x       x       44.58   34.69   24.80   14.92   5.03
48       80.00   x       x       x       x       45.99   38.24   30.49   22.74
49       81.00   x       x       x       x       x       x       46.07   40.45
50       82.00   x       x       x       x       x       x       x       x

Total Extreme Values: 0

Deg. C   Deg. F  40%     50%     60%     70%     80%     90%     100%
45       77.00   99.68   99.21   98.74   98.27   97.80   97.32   96.85
46       78.00   101.06  100.58  100.10  99.61   99.13   98.65   98.17
47       79.00   102.43  101.93  101.44  100.95  100.46  99.96   99.47
48       80.00   103.78  103.28  102.78  102.27  101.77  101.27  100.76
49       81.00   105.13  104.61  104.10  103.59  103.07  102.56  102.04
50       82.00   106.46  105.93  105.41  104.89  104.36  103.84  103.31

Total Extreme Values: 0

note: one glaring error is your integer division error in your conversion to Fahrenheit. You can remedy that by insuring floating point division of your conversion factor:

celsius_f = (celsius * (9.0 / 5)) + 32;

Making that one change will have a dramatic impact on your calculations, e.g.

$ ./bin/windchill
Input a range of temps in deg. C, (e.g. t1 t2): 45 50

Deg. C   Deg. F  5mph    10mph   15mph   20mph   25mph   30mph   35mph   40mph
45       113.00  x       x       x       x       x       x       x       x
46       114.80  x       x       x       x       x       x       x       x
47       116.60  x       x       x       x       x       x       x       x
48       118.40  x       x       x       x       x       x       x       x
49       120.20  x       x       x       x       x       x       x       x
50       122.00  x       x       x       x       x       x       x       x

Total Extreme Values: 0

Deg. C   Deg. F  40%     50%     60%     70%     80%     90%     100%
45       113.00  170.20  168.93  167.65  166.37  165.09  163.81  162.53
46       114.80  173.15  171.84  170.54  169.23  167.92  166.61  165.30
47       116.60  176.09  174.75  173.42  172.08  170.74  169.40  168.06
48       118.40  179.01  177.65  176.28  174.92  173.55  172.18  170.81
49       120.20  181.92  180.53  179.14  177.74  176.35  174.95  173.56
50       122.00  184.82  183.40  181.98  180.55  179.13  177.71  176.28

Total Extreme Values: 0

You have some more work to do... You can start by reviewing The Heat Index Equation (which appears to be where your constants come from -- but note you are missing the correction factors and you need to pay careful attention to the units of humidity). Then follow up by looking at Wind Chill paying careful attention to the exponent on the wind. When you correct your formula, you will then need to link against the math library, so add -lm to your compile string. (that's little-'L'm). Once you correct your logic, you should see something similar to the following output.

(note: with the extreme values over a temperature range from -20 to 50, I get 164 wind_chill extremes and 332 heat_index extremes)

$ ./bin/windchill
Input a range of temps in deg. C, (e.g. t1 t2): 10 45

Wind Chill:

Deg. C   Deg. F  5mph    10mph   15mph   20mph   25mph   30mph   35mph   40mph
10       50.00   47.77   45.59   44.19   43.15   42.31   41.59   40.98   40.43
11       51.80   49.87   47.80   46.48   45.50   44.70   44.02   43.44   42.92
12       53.60   51.96   50.02   48.77   47.84   47.09   46.45   45.90   45.41
13       55.40   54.06   52.23   51.06   50.19   49.48   48.88   48.36   47.90
14       57.20   56.16   54.45   53.35   52.53   51.87   51.31   50.82   50.39
15       59.00   58.26   56.66   55.64   54.88   54.26   53.74   53.28   52.88
16       60.80   60.36   58.88   57.93   57.22   56.65   56.16   55.74   55.37
17       62.60   62.45   61.09   60.22   59.57   59.04   58.59   58.21   57.86
18       64.40   x       63.30   62.51   61.91   61.43   61.02   60.67   60.35
19       66.20   x       65.52   64.80   64.26   63.82   63.45   63.13   62.85
20       68.00   x       67.73   67.09   66.60   66.21   65.88   65.59   65.34
21       69.80   x       x       69.38   68.95   68.60   68.31   68.05   67.83
22       71.60   x       x       x       71.29   70.99   70.74   70.51   70.32
23       73.40   x       x       x       x       73.38   73.16   72.98   72.81
24       75.20   x       x       x       x       x       x       x       x
...

Total Extreme Values: 0

Heat Index:

Deg. C   Deg. F  40%     50%     60%     70%     80%     90%     100%
...
26       78.80   x       x       x       x       x       x       x
27       80.60   80.35   81.35   82.55   83.94   85.53   87.32   89.31
28       82.40   81.80   83.21   85.01   87.20   89.78   92.75   96.10
29       84.20   83.49   85.39   87.86   90.91   94.53   98.74   103.51
30       86.00   85.44   87.89   91.10   95.07   99.80   105.29  111.55
31       87.80   87.64   90.71   94.72   99.68   105.58  112.42  120.21
32       89.60   90.10   93.85   98.73   104.74  111.86  120.11  129.49
33       91.40   92.81   97.32   103.13  110.25  118.66  128.38  139.39
34       93.20   95.77   101.11  107.92  116.20  125.97  137.21  149.92
35       95.00   98.99   105.22  113.09  122.61  133.78  146.60  161.07
36       96.80   102.46  109.65  118.65  129.47  142.11  156.57  172.84
37       98.60   106.18  114.40  124.60  136.78  150.95  167.10  185.24
38       100.40  110.16  119.47  130.93  144.54  160.30  178.20  198.26
39       102.20  114.39  124.87  137.65  152.75  170.15  189.87  211.90
40       104.00  118.88  130.58  144.76  161.40  180.52  202.11  226.17
41       105.80  123.62  136.62  152.25  170.51  191.40  214.91  241.05
42       107.60  128.61  142.98  160.13  180.07  202.79  228.28  256.56
43       109.40  133.85  149.66  168.40  190.08  214.68  242.22  272.70
44       111.20  139.35  156.66  177.06  200.53  227.09  256.73  289.45
45       113.00  145.10  163.99  186.10  211.44  240.01  271.81  306.83

Total Extreme Values: 97

Look things over and let me know if you have further questions.

Upvotes: 1

Marcin Zdunek
Marcin Zdunek

Reputation: 1011

Look here:

celsius_f=(celsius*(9/5))+32;

In C 9/5 is not equal to 9/5 as in real math, here integer divided by integer is equal to integer too, rounded to lower value. So here 9/5 is equal to 1, not 1.8. You should use float variable type, for example

celsius_f=(celsius*(9.0/5))+32;

Another mistake is here:

compute_wind_chill(num1, num2);
printf("\nTotal Extreme Values: %d", ext1);

You are displaying float result as integer.

Upvotes: 0

Related Questions