Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I properly use the 0.0 in an if statement

Tags:

c

if-statement

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.

like image 929
Jade Avatar asked Oct 14 '25 03:10

Jade


2 Answers

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);
like image 63
chux - Reinstate Monica Avatar answered Oct 19 '25 08:10

chux - Reinstate Monica


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.)

like image 28
Ray Avatar answered Oct 19 '25 10:10

Ray