Roman Savushkin
Roman Savushkin

Reputation: 21

How add two times in c?

I am trying to add two times like 20:30 + 1:40 = 22h 10m. I'm having a problem with the remainder after the dot

#include <stdio.h>

float walking (float start,float duration);

int main() {
  printf ("finish = %.2f", walking(20.30, 1.40));
  return 0;
}

float walking(float start, float duration) {
  int finMinuites = (int)(start * 100) % 100 + (int)(duration * 100) % 100;
  int finHours = (start * 100) / 100 + (duration * 100) / 100;

  if (finMinuites >= 60) {
    finMinuites -= 60;
    finHours++;
  }

  if (finHours >= 24)
    finHours -= 24;

    return finHours + finMinuites / 100;
  }

Upvotes: 1

Views: 361

Answers (3)

Fe2O3
Fe2O3

Reputation: 8344

As suggested by @ryyker, you can make life simple with strings without changing the calling parameters:

#include <stdio.h>
#include <stdlib.h>

double walking( double bgn, double dur ) {
    printf( "Start = %5.2f  duration = %5.2f  ", bgn, dur );
    char str[32];

    sprintf( str, "%.2f %.2f", bgn, dur );
    int res = 0, cnt = 1;
    for( char *cp = str; ( cp = strtok( cp, " ." ) ) != NULL; cp = NULL )
        res += atoi( cp ) * (cnt&1 ? 60 : 1), cnt++;

    return res/60%24 + ((res%60)*0.01);
}

int main( void ) {
    double pairs[][2] = {
        { 20.30,  1.40 },
        {  1.47,  1.13 },
        {  0.00,  1.13 },
        {  0.00,  0.00 },
        { 23.59,  0.01 },
        { 12.00, 48.27 },
    };

    for( int i = 0; i < sizeof pairs/sizeof pairs[0]; i++ )
        printf ( "finish = %5.2f\n", walking( pairs[i][0], pairs[i][1] ) );

    return 0;
}

Output

Start = 20.30  duration =  1.40  finish = 22.10
Start =  1.47  duration =  1.13  finish =  3.00
Start =  0.00  duration =  1.13  finish =  1.13
Start =  0.00  duration =  0.00  finish =  0.00
Start = 23.59  duration =  0.01  finish =  0.00
Start = 12.00  duration = 48.27  finish = 12.27

It has been noted that this approach may not work for Dr Who and other time travellers able to travel into the past. The following shows the necessary changes for those for whom the second law of thermodynamics does not apply:

sprintf( str, "%.2f %.2f", bgn, dur );
int res = 0, cnt = 1, sgn = 1;
for( char *cp = str; ( cp = strtok( cp, " ." ) ) != NULL; cp = NULL, cnt++ )
    res += atoi( cp )
        * (cnt&1 ? 60 : 1)
        * sgn,
    sgn = *cp == '-' ? -1 : 1;

/* then one additional test case */

    { 12.00, -2.30 },

/* Output of the single test case: */

Start = 12.00  duration = -2.30  finish =  9.30

Since the first parameter shown in the OP seems to use a 24hr clock, no attempt has been made to test starting at "minus eleven-thirty".

Enjoy your walk. Take the garbage out with you when you leave...

Upvotes: 0

chux
chux

Reputation: 153478

The difficult part is to break a floating point variable (FP) properly.

float/double cannot represent many values like 0.01 exactly and so (int)(start * 100) fails edge cases when the minutes * 100 are a fraction just less than a whole number as (int) truncates.

Instead break the FP value into whole and fraction parts (modf()) to get the hours and minutes and then form a total single unit time value. Add. Then convert the sum back to hours.minutes.

Makes more sense to use double than float given OP is using double test case constants. Also float should be reserved for compelling conditions that require/benefit from them instead of the default double.

No need to scale to minutes. Makes for simpler code. Easy-peasy.

#include <math.h>

double to_hours(double hours_dot_minutes) {
  double h;
  double m = modf(hours_dot_minutes, &h) * 100.0;
  return h + m/60.0;
}

double reduce_to_a_day(double hours) {
  const double hours_per_day = 24.0;
  hours = fmod(hours, hours_per_day);
  if (hours < 0.0) {
    hours += hours_per_day;
  }
  return hours;
}

double to_hours_dot_minutes(double hours) {
  double h;
  double m = modf(hours, &h) * 60.0;
  return h + m/100.0;
}

double walking(double start, double duration) {
  double sum = to_hours(start) + to_hours(duration);
  sum = reduce_to_a_day(sum);
  return to_hours_dot_minutes(sum);
}

Notice that int math is not used anywhere. IMO, floating point problems best handled with FP math, integer problems with integer math and text problems with text manipulation. Mixing approaches often encounters issues in edge cases - as in OP's use of (int) for a FP problem.


If still wanting to use a cast over a limited range of values,

double walking(double start, double duration) {
  int start_h = (int) start;
  int duration_h = (int) duration;
         
  double sum = start_h + duration_h + 
      ((start - start_h) + (duration - duration_h)) * 100.0 / 60.0;
  while  (sum >= 24.0) sum -= 24.0;
  int sum_h = (int) sum;
  return sum_h + (sum - sum_h) * 60.0 / 100.0;
}

Upvotes: 2

kess
kess

Reputation: 1309

If you really want to store time in a float then here is a solution:

#include<stdio.h>
#include<math.h>

float walking(float start,float duration);
int main() {
    printf("finish = %.2f",walking(20.30, 1.40));
    return 0;
}
int toMinutes(float time){
    int t = (int)round((time*100));
    int hours = t/100;
    int min = t - hours * 100;
    return hours*60+min;
}
float toFloat(int minutes){
    int hours = minutes/60;
    int min = minutes - hours * 60;
    float t = hours * 100;
    t += min;
    t /= 100;
    return t;
}
float walking(float start,float duration){
    int mins = toMinutes(start) + toMinutes(duration);
    int day = 24*60;
    while(mins > day){
        mins -= day;
    }

    return toFloat(mins);
}

But I would suggest storing the minutes as an int instead.

Upvotes: 1

Related Questions