Combine if statements with logically related conditions

97 views Asked by At

I have this situation.

**Updated my code and it works in all the way i want it to. *clarified the code as requested(full program)

if i give

Start time: 2:30:30

Stop time: 2:30:25

i should get

elapsed: 23:59:55

get it? it crossed midnight...into the next day....

thats wht i wanted and it works!

I have these five if statements with logically related conditions.

The program was giving the desired output, but is it possible to combine these if statements in any way (other than using 'OR' OPERATORS and making huge conditions; like nested-if or maybe conditional operators.

//time elapsed program
//including support for time crossing midnight into the next day
#include<stdio.h>

struct time
{
  int hour;
  int minute;
  int second;
};

struct time timeElapsed(struct time, struct time);

int main()
{
  struct time start, stop, elapse;

  printf("Enter start time (hh:mm:ss)  :  ");
  scanf("%d:%d:%d", &start.hour, &start.minute, &start.second);
  printf("Enter stop  time (hh:mm:ss)  :  ");
  scanf("%d:%d:%d", &stop.hour, &stop.minute, &stop.second);

  elapse = timeElapsed(start, stop);

  printf("The time elapsed is          :  %.2d:%.2d:%.2d", elapse.hour, elapse.minute, elapse.second);

  return 0;
}

struct time timeElapsed(struct time begin, struct time end)
{
  struct time elapse;

  if(end.hour < begin.hour)
    end.hour += 24;

  if(end.hour == begin.hour  &&  end.minute < begin.minute)
    end.hour += 24;

  if(end.hour == begin.hour  &&  end.minute == begin.minute  &&  end.second < begin.second)
    end.hour += 24;

  if(end.second < begin.second)
  {
    --end.minute;
    end.second += 60;
  }

  if(end.minute < begin.minute)
  {
    --end.hour;
    end.minute += 60;
  }

  elapse.second = end.second - begin.second;
  elapse.minute = end.minute - begin.minute;
  elapse.hour = end.hour - begin.hour;

  return elapse;
}
4

There are 4 answers

0
M.M On

Logically you are comparing whether the end time is earlier than the begin time.

If you can convert the three numbers to one via a mapping that preserves the order then you will be able to use a single comparison.

In this case , converting to the total number of seconds stands out:

if (   end.hour * 3600L +   end.minute * 60 +   end.second
   < begin.hour * 3600L + begin.minute * 60 + begin.second )

This may or may not be more efficient than your original code. If you are going to do this regularly then you could make an inline function to convert a time to the total seconds.

0
Tom Goodfellow On

So the first three tests amount to checking for "end < begin". Assuming the fields are already validated to be within range (i.e. .minute and .second both 0..59) why not convert to seconds and compare them directly, e.g.:

if((end.hour * 3600 + end.minute * 60 + end.second) < 
   (begin.hour * 3600 + begin.minute * 60 + begin.second))

To me this is more obvious as source, and on a modern CPU probably generates better code (i.e. assuming that branches are expensive and integer multiplication is cheap)

To see how the two approaches compare here's a Godbolt version of two such comparison functions compiled with Clang 3.9 -O3 (21 vs 11 instructions, I didn't count the code bytes or try to guesstimate execution time).

https://godbolt.org/g/Ki3CVL

0
chux - Reinstate Monica On

Code below differs a bit from OP's logic, but I think this matches the true goal (perhaps not)


Subtract like terms and scale. By subtracting before scaling, overflow opportunities reduced.

#define MPH 60
#define SPM 60
int cmp = ((end.hour - begin.hour)*MPH + (end.minute - begin.minute))*SPM +
    (end.second - begin.second);

if (cmp < 0) Time_After();
else if (cmp > 0) Time_Before();
else Time_Same();    
2
coredump On

Keeping your approach, I would do as follows. This is not much different, but there are two main branches: one where end definitely does not need to be modified because it happens after begin or at the same time (so that the difference is 0:0.0), and another where fields are adjusted to take account modular arithmetic.

struct time timeElapsed (struct time begin, struct time end)
{
  if ((end.hour >= begin.hour) &&
      (end.minute >= begin.minute) &&
      (end.second >= begin.second)) {
    /* end is greater or equal to begin, nothing to adjust. */
  } else {
    end.hour +=24;

    if (end.second < begin.second) {
      --end.minute;
      end.second += 60;
    }

    if (end.minute < begin.minute) {
      --end.hour;
      end.minute += 60;
    }
  }

  struct time elapsed = {
    end.hour - begin.hour,
    end.minute - begin.minute,
    end.second - begin.second
  };
  return elapsed;
}