Reputation: 7
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
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
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