0

I'm creating a temperature converter in C. Basically, you input a minimum and maximum value in degrees Celsius, along with a step, and it displays that information in a list, along with the Fahrenheit equivalent. On some occasions, I have noticed the last Fahrenheit entry not being displayed when it should. For example, when you input a lower limit of 10, a higher limit of 30, and a step of 4, it cuts off the last Fahrenheit temperature. I know it's something to do with the last while loop, but I just can't figure it out.

#include <stdio.h>

int main (int argc, const char * argv[]) {
double l, h, s;
double lf, hf, sf;
/* Number rows in tables */
int num1, num2;
num1 = 1;
num2 = 1;

/* Lower limit input */
printf("Please give a lower limit: ");
scanf("%4lf", &l);
while (l < 0) {
        printf("Lower limit must be greater than 0: ");
        scanf("%4lf", &l);
}

/* Stores value for Fahrenheit conversion */
lf = l;

/* Higher limit input */
printf("Please give a higher limit: ");
scanf("%4lf", &h);
while (h <= l) {
        printf("Higher limit must be greater than lower limit: ");
        scanf("%4lf", &h);
}

while (h >= 50000) {
        printf("Higher limit must be less than 50000: ");
        scanf("%4lf", &h);
}

hf = h;

/* Step input */
printf("Please input step: ");
scanf("%4lf", &s);
while (s <= 0) {
        printf("Step must be greater than 0: ");
        scanf("%4lf", &s);
}

while (s >= h - l) {
        printf("Step must be less than the difference in temperatures: ");
        scanf("%4lf", &s);
}

sf = s;

/* Celsius table */
printf("\nCelsius\n-------\n");
while (l <= h) {
    printf("%i. %4lf\n", num1, l);
    num1++;
    l = l + s;
}

/* Fahrenheit table */
printf("\nFahrenheit\n----------\n");
/* Converts Celsius to Fahrenheit */
lf = (lf * 1.8) + 32;
hf = (hf * 1.8) + 32;
sf = sf * 1.8;
printf("Lower input: %4lf\n", lf);
printf("Higher input: %4lf\n", hf);
printf("Step: %4lf\n----------\n", sf);
/* This while loop sometimes cuts off the last entry */
while (lf <= hf) {
    printf("%i. %4lf\n", num2, lf);
    num2++;
    lf = lf + sf;
}

return 0;

}
1
  • No. I'm just learning on my own. Commented Aug 19, 2011 at 0:47

4 Answers 4

3

The problem is with comparing the doubles, you might get into a situation where something like 10 + 1.8 evaluates to 11.800000001 and thus missing the end value.

The solution to your problem would be to first calculate the number of steps:

int steps = (h - l) / s + 1; //Might want to apply rounding

And then use a for/while loop over the integer variable instead:

for (int i = 0; i < steps; ++i) {
    double t = l + (h - l) * i / (steps - 1);
}

for (int i = 0; i < steps; ++i) {
    double tf = lf + (hf - lf) * i / (steps - 1);
}
Sign up to request clarification or add additional context in comments.

3 Comments

This. You should use integers for ordinals, like the number of times to execute a loop.
I understand the code calculating the number of steps, but the for/while loop is less clear. double t displays inconsistent results. For example, inputting a lower limit of 10, a higher limit of 20, and a step of 2, displays 10.000000, 12.500000, 15.000000, etc.
@Ben Should have been a + 1 in the steps calculation, fixed.
2
while (lf <= hf) 

You are comparing Double values, You will face problems of Precison & Rounding Errors, Most likely that causes the last iteration to not execute at all.

This answer of mine, should be a good read.

7 Comments

and what is the solution to this problem?
To add to this, generally with precision you'll want to compare to an epsilon: some small value that shows the tolerance. So instead of while (lf <= hf) you might try while (lf - hf <= .001)
@duedl0r: I updated the answer with an link, which will explain you the problem and the solution.
This explains why the author used integers for his solution (this is a programming challenge from a book). My code works, but is far from elegant. I like Stefan Mai's suggestion.
@Ben: Did you read the link to the previous answer? Actually, It suggests abs(x - y) < epsilon, which is more or less same as what Stefan suggested, just it is more in a C++ way way of doing things because that Q was tagged c++.
|
0

Choose a precision and compare it with the difference between hf and lf(abs value). Also keep in mind with a random fixed step you will not always reach the top value of the interval. it might work if step divides h-l but it won't work otherwise.

Comments

0

Directly after your last while loop, add the following code (and don't forget to #include assert.h):

printf("lf = %f, hf = %f\n", lf, hf);
assert(lf == hf);

you should get this output:

Celsius
-------
1. 10.000000
2. 14.000000
3. 18.000000
4. 22.000000
5. 26.000000
6. 30.000000

Fahrenheit
----------
Lower input: 50.000000
Higher input: 86.000000
Step: 7.200000
----------
1. 50.000000
2. 57.200000
3. 64.400000
4. 71.600000
5. 78.800000
lf = 86.000000, hf = 86.000000
Assertion failed: lf == hf, file randomdudescode.c, line 77

Which is incredibly confusing, because obviously lf == hf. This illustrates one of the quirks of C and floating point tomfoolery in general. You have to deal with rounding errors and imprecision.

Comments

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.