int main () {
float hour, dec, Dec_Only, min2, sec;
int res, r, min, whole, min3, sec2, sec3;
printf ("Enter hours: ");
scanf ("%f", &hour);
//Displaying initial minutes
min = hour * 60;
printf ("%d minutes\n", min);
if (hour == 0.0){
res = min / 60;
r = min % 60;
printf("%02d : %02d : 00", res, r);
}
else {
//Getting hours
whole = (int)hour;
dec = (hour - whole) * 100;
//Getting minutes
Dec_Only = hour - whole;
min2 = Dec_Only * 60;
min3 = (int)min2;
//Getting seconds
sec = min2 - min3;
sec2 = sec * 60;
sec3 = (int)sec2;
printf ("%02d : %02d : %02d", whole, min3, sec3 );
}
return 0;
}
Hello, Im new in C. My work is about converting the hours into a digital clock (where Im required to use Conditional Statements). I added a conditional statement when the user_input only contains 1 decimal or more. My code works, however, when I enter the specific number 5.2, thats when the problem comes in.
Enter hours (user_input): 5.2 Output: 05 : 11 : 59
My desired output: 05: 12 : 00
PS: When I enter any other numbers it works.
The key problem is that entering "5.2"
results in a float
near, but nor exactly, 5.2. This is because float
is encoded as a finite integer times a power-of-2 and cannot encode 5.2. 5.19999980926513671875 (which is 5,452,595 * 2-20) is commonly closest.
Instead of min = hour * 60
, which assigns a truncated value to min
, use min = lroundf(hour * 60);
(from <math.h>
) to round the float
product to the nearest long
.
Rest of code should not use hours
or floating-point math again. Just use integer math.
Even better: convert hours
into a whole number of seconds first.
#define SEC_PER_HOUR_FP (60.0 * 60)
long total = lround(hour * SEC_PER_HOUR_FP);
int s = total%60;
total /= 60;
int m = total%60;
total /= 60;
long h = total;
printf ("%02ld : %02d : %02d", h, m, s);
The float vs double stuff mentioned in the comments is just masking the problem. The real issue is that "0.2" cannot be exactly represented in binary floating point. Much like how 1/3 can't be represented using a finite expansion in base 10 (0.333...), 2/10 is 0.001100110011... in base 2. So you need an infinite number of bits to store 0.2 exactly, and since you don't have that, you get rounding errors whenever you do arithmetic on it.
Using double increases the number of bits you have, and might decrease the rounding error by enough that you get the right answer in this particular case, but it doesn't eliminate it. Some amount of rounding error has already happened as soon as you read the number in: hour
is not 5.2; it's 5.19999980926513671875. (If you used float, there would be even more initial error.)
What you want to do is convert to an integral representation as soon as possible to avoid accumulating more rounding error.
unsigned long seconds = round(hour * 60.0 * 60.0);
(round is in math.h).
If you just assign hour * 60.0 * 60.0
to seconds, it'll truncate instead of rounding: 18719.999313354492187 becomes 18719 instead of 18720: that's where your missing second comes from. round
rounds it to the nearest integer instead of truncating to the next lowest. Once you've got seconds as an unsigned long, all your arithmetic will be integer division (which truncates to just the amount that divided evenly) and modulo (the remainder), which give results that can be exactly represented by the machine.
Eventually, you'll want to read What Every Computer Scientist Should Know About Floating-Point Arithmetic. If you just started, it might be a bit above your level, but give it a shot and if you don't understand it, come back and try again after you've got a bit more experience.
(Also, include newlines in those printf calls. I'm guessing you're using an IDE that automatically puts a newline after its output, but if you run this on the command line, that newline will be missing.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With