Of subtitles & lag times (yet another C overflow doubt) - c

I'm trying to calculate the time offset to be added to subtitle files to correct the lag. The part shown below is after tokenizing the hh:mm:ss,uuu (uuu stands for microseconds) into the time[] array. I'm converting the time into microseconds then adding the actual & lag time to get the final time.
The program computes the actual & lag time properly. However, it gives the wrong final hour time. Have I hit upon some overflow condition that can't be handled by the code below?
Edit: I have realized the error. I should be dividing rather than taking remainder for hour time.
int i;
int time[4];
unsigned long totalTime,totalLagTime;
...
for(i=0;i<4;i++)
{
printf("time[%d] = %d\n",i,time[i]);
}
for(i=0;i<4;i++)
{
printf("lag time[%d] = %d\n",i,lagTime[i]);
}
totalTime = 1000*(3600*time[0] + 60*time[1] + time[2]) + time[3];
printf("total time is %u in milliseconds\n",totalTime);
totalLagTime = 1000*(3600*lagTime[0] + 60*lagTime[1] + lagTime[2]) + lagTime[3];
printf("total lag time is %u in milliseconds\n",totalLagTime);
totalTime += totalLagTime;
printf("Now, total time is %u in milliseconds\n",totalTime);
time[0] = totalTime % 3600000;
printf("hour time is %d\n",time[0]);
Test case:
00:01:24,320
time[0] = 0
time[1] = 1
time[2] = 24
time[3] = 320
lag time[0] = 10
lag time[1] = 10
lag time[2] = 10
lag time[3] = 10
total time is 84320 in milliseconds
total lag time is 36610010 in milliseconds
Now, total time is 36694330 in milliseconds
hour time is 694330

Shouldn't that be
time[0] = totalTime / 3600000;

You have a logic error: 36694330 mod 3600000 really is 694330.
What are you trying to do, exactly?

Related

Combine if statements with logically related conditions

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;
}
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.
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
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();
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;
}

PIC Microcontroller using C

I am trying to get this code to work in MM:SS:FFFFFF, where MM is minutes, SS seconds and FFFFFF micro seconds, but my minutes are bot working properly. Instead of getting anything like 01:05:873098 I get 00:65_873098. Thanks for any tip.
#include <prototype.h>
int16 overflow_count;
#int_timer1
void timer1_isr(){
overflow_count++;
}
void main(){
int32 time;
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
enable_interrupts(int_timer1);
while(TRUE){
enable_interrupts(global);
while(input(PUSH_BUTTON)); //Wait for press
set_timer1(0);
overflow_count=0;
while(!input(PUSH_BUTTON)); //WAIT FOR RELEASE
disable_interrupts(global);
time=get_timer1();
time=time+((int32)overflow_count<<16);
time-=15; //substract overhead
printf("Time is %02lu:%02lu.%06lu minutes.\r\n",
time/1000000000, (time/6000000), (time/5)%1000000);
}
}
I would suggest that you introduce some intermediate variables like "ticks", "microsecs", "secs", and "mins". Do the calculations step by step, from smallest unit to largest, remembering to subtract off each part before converting the next larger part. Make sure the units work out at each step of the conversion (e.g. don't add or subtract values that have different units). Think about how you'd do it with pencil and paper: probably not the way you've written it! When you break it down like that, it will be easier to get the logic correct.
you aren't ever subtracting out the whole parts
if time is time in micro's... something like:
time = time % (24 * 60 * 60 * 1000); //mod out any extra days
int hours = time / (60 * 60 * 1000);
time = time % (60 * 60 * 1000); // or time -= hours*(60 * 60 * 1000)
int min = time / (60 * 1000);
time = time % (60 * 1000); // or time-= min*(60*1000)
...

Self-correcting periodic timer using gettimeofday()

I have a loop which runs every X usecs, which consists of doing some I/O then sleeping for the remainder of the X usecs. To (roughly) calculate the sleep time, all I'm doing is taking a timestamp before and after the I/O and subtract the difference from X. Here is the function I'm using for the timestamp:
long long getus ()
{
struct timeval time;
gettimeofday(&time, NULL);
return (long long) (time.tv_sec + time.tv_usec);
}
As you can imagine, this starts to drift pretty fast and the actual time between I/O bursts is usually quite a few ms longer than X.
To try and make it a little more accurate, I thought maybe if I keep a record of the previous starting timestamp, every time I start a new cycle I can calculate how long the previous cycle took (the time between this starting timestamp and the previous one). Then, I know how much longer than X it was, and I can modify my sleep for this cycle to compensate.
Here is how I'm trying to implement it:
long long start, finish, offset, previous, remaining_usecs;
long long delaytime_us = 1000000;
/* Initialise previous timestamp as 1000000us ago*/
previous = getus() - delaytime_us;
while(1)
{
/* starting timestamp */
start = getus();
/* here is where I would do some I/O */
/* calculate how much to compensate */
offset = (start - previous) - delaytime_us;
printf("(%lld - %lld) - %lld = %lld\n",
start, previous, delaytime_us, offset);
previous = start;
finish = getus();
/* calculate to our best ability how long we spent on I/O.
* We'll try and compensate for its inaccuracy next time around!*/
remaining_usecs = (delaytime_us - (finish - start)) - offset;
printf("start=%lld,finish=%lld,offset=%lld,previous=%lld\nsleeping for %lld\n",
start, finish, offset, previous, remaining_usecs);
usleep(remaining_usecs);
}
It appears to work on the first iteration of the loop, however after that things get messed up.
Here's the output for 5 iterations of the loop:
(1412452353 - 1411452348) - 1000000 = 5
start=1412452353,finish=1412458706,offset=5,previous=1412452353
sleeping for 993642
(1412454788 - 1412452353) - 1000000 = -997565
start=1412454788,finish=1412460652,offset=-997565,previous=1412454788
sleeping for 1991701
(1412454622 - 1412454788) - 1000000 = -1000166
start=1412454622,finish=1412460562,offset=-1000166,previous=1412454622
sleeping for 1994226
(1412457040 - 1412454622) - 1000000 = -997582
start=1412457040,finish=1412465861,offset=-997582,previous=1412457040
sleeping for 1988761
(1412457623 - 1412457040) - 1000000 = -999417
start=1412457623,finish=1412463533,offset=-999417,previous=1412457623
sleeping for 1993507
The first line of output shows how the previous cycle time was calculated. It appears that the first two timestamps are basically 1000000us apart (1412452353 - 1411452348 = 1000005). However after this the distance between starting timestamps starts looking not so reasonable, along with the offset.
Does anyone know what I'm doing wrong here?
EDIT: I would also welcome suggestions of better ways to get an accurate timer and be
able to sleep during the delay!
After some more research I've discovered two things wrong here-
Firstly, I'm calculating the timestamp wrong. getus() should return like this:
return (long long) 1000000 * (time.tv_sec + time.tv_usec);
And secondly, I should be storing the timestamp in unsigned long long or uint64_t.
So getus() should look like this:
uint64_t getus ()
{
struct timeval time;
gettimeofday(&time, NULL);
return (uint64_t) 1000000 * (time.tv_sec + time.tv_usec);
}
I won't actually be able to test this until tomorrow, so I will report back.

converting integers to minutes

I am new to C programming, but experienced in Java. I am creating a simple console application to calculate time between two chosen values. I am storing the chosen values in an int array like this:
static int timeVals[] = {748,800,815,830,845,914,929,942,953,1001,1010,1026,1034,1042,1048};
I am calling a method diff to calculate the time between to values liek this:
int diff (int start, int slut) {
/* slut means end in danish. not using rude words, but I am danish */
int minutes = 0;
int time = 0;
double hest;
hest = (100/60);
printf("hest = %f", hest);
if(timeVals[start] > timeVals[slut])
{
minutes = timeVals[start] - timeVals[slut];
/* printing hest to see what the value is */
printf("t = %f",hest);
time = minutes * (100/60);
printf("minut diff: %d\n", time);
}
else
{
minutes = timeVals[slut] - timeVals[start];
tiem = time + (minutes * (100/60));
}
return time;
}
The weird thing is that when I print out hest value I get 1.000000, which I mean isn't right... I have been struggling with this for hours now, and I can't find the issue.. maybe I'm just bad at math :P
hope you can help me
The issue is
hest = (100/60)
This result will be 1 because 100 / 60 = 1.6666...., but this is integer division, so you will lose your decimals, so hest = 1. Use
hest = (100.0 / 60.0)
Same with
time = minutes * (100/60);
Changed to
time = minutes * (100.0 / 60.0);
In this case again, you will lose your decimals because time is an int.
Some would recommend, if speed is an issue, that you perform all integer calculations and do store all your items as ints in 1/100th's of a second (i.e. 60 minutes in 1/100ths of a second = 60 minutes*60 seconds*100)
EDIT: Just to clarify, the link is for C++, but the same principles apply. But on most x86 based systems this isn't as big of a deal as it is on power limited embedded systems. Here's another link that discusses this issue
Following statement is a NOP
time = minutes * (100/60);
(100 / 60) == 1 because 100 and 60 are integers. You must write this :
time = (minutes * 100) / 60;
For instance if minutes == 123 time will be calculated as (123 * 100) / 60 which is 12300 / 60 which is 205.
As stated, you are mixing floating point and integer arithmetic. When you divide two integers, your result is integer, but you are trying to print that result as float. You might consider using the modulus operator (%) and compute quotient and remainder,
int // you might want to return float, since you are comingling int and float for time
diff (int start, int slut)
{
/* slut means end in danish. not using rude words, but I am danish */
int minutes = 0, seconds = 0, diff;
int time = 0;
double hest = (100.0) / (60.0); //here
printf("hest = %f", hest);
if(timeVals[start] > timeVals[slut])
{
diff = timeVals[start] - timeVals[slut];
time = diff * (100.0/60.0);
minutes = diff/60;
seconds = diff%60; //modulus (remainder after division by 60
}
else
{
diff = timeVals[slut] - timeVals[start];
time = time + diff * (100.0/60.0);
minutes = diff/60;
seconds = diff%60; //modulus (remainder after division by 60
}
/* printing hest to see what the value is */
printf("t = %f",hest);
printf("minut:seconds %d:%02d\n", minutes, seconds );
printf("minut diff: %d\n", time);
return time;
}

Doubling a variable numerous times, and adding all iterations of the variable together

EDITED FOR CLARITY'S SAKE. I APOLOGIZE FOR THE CONFUSION :3
Okay, so I'm following an online CS class, and we're supposed to write a program, in C, that will tell you how much money you'd have if you had a penny at the beginning of the month and doubled it every day.
Each day you would get double what you had yesterday PLUS everything from the previous days.
Example: You start with .01 and what to calculate a running total by day 3. So the first day is .01, second day is .02, third day is .04. On day 3 you would have 0.01+0.02+0.04 (.09).
The program intends to calculate this process over the duration of any given month (28 - 31 days).
I'm having a really hard time trying to implement this. I've got it doubling it, but I'm not sure how to the previously-calculated days together.
Here's my code:
#include <stdio.h>
#include <math.h>
int main(void) {
/*days represents total days in months*/
/*pens represents the number of pennies on the first day*/
long long days;
long long pens;
do {
printf("Enter the number of days in the month: ");
scanf("%llu", &days);
} while(days < 28 || days > 31);
printf("Enter the initial number of pennies: ");
scanf("%llu", &pens);
for (int i=0; i<= days-1; i++) {
pens += pow(2,i);
printf("You'll have $%llu\n", pens);
}
}
edit2: Okay, so I think I fixed it thanks to all your awesome advice. I changed the last part to:
for (int i=0; i<= days-1; i++)
{
pens = pens + (pens * 2);
}
total = pens / 100;
printf("You'll have $%.2f\n", total);
}
Though there is still a slight issue with the output (which, I'm thinking, is due to the data type I'm using?)
It prints out:
You'll have $0.00
You'll have $0.00
You'll have $0.00
You'll have $0.00
You'll have $2.00
You'll have $7.00
You'll have $21.00
You'll have $65.00
You'll have $196.00
You'll have $590.00
You'll have $1771.00
You'll have $5314.00
You'll have $15943.00
You'll have $47829.00
You'll have $143489.00
You'll have $430467.00
You'll have $1291401.00
You'll have $3874204.00
etc.
Pretty good, but I'm betting it's not that accurate since the first few iterations are 0.00.
Well, let's translate what you have to do into pseudocode:
var daily_amount = 0.01
var total = daily_amount
iteration_over_days:
daily_amount *= 2
total += daily_amount
From there, all you need to do is translate to C.
Enjoy!
Instead of using the long datatype, you can also start at 1 and then at the end divide by 100: $0.01 -> $1
I think the following line needs change:
pens+=pow(2,i);
It should be:
pens = pens + (pens * 2)
The logic is that if you start with 1 penny on day 1, then it will be something like this
Day 1 : 1 + (1 * 2) = 3
Day 2 : 3 + (3 * 2) = 9
Day 3 : 9 + (9 * 2) = 27
and so on..
I hope this is the logic which you are expecting. By doing pow(2,i), you are just adding square of the day count to your total money each day which does't seem to be the expected logic based on your question.
This is the code you are looking at:
total = 0;
for (int i = 1; i <= days; i++) {
total += pens;
pens = pens*2;
}
printf("You'll have $%d\n", total);
Don't compute the power each time! Just keep track of a running count and double it every day.
Here's the core of the algorithm you need for total_days number of days:
typedef unsigned long long int my_uint;
my_uint initial_payment = 1;
my_uint total_pennies = 0;
for (my_uint day_payment = initial_payment, day = 0; days != total_days; ++day)
{
total_pennies += day_payment;
day_payment *= 2;
}
// now have total_pennies
Of course you could notice that 1 + q + q2 + q3 + ... + qN − 1 is the same as (qN − 1) / (q − 1) and thus compute the answer in one single step (e.g. for q = 2 in your case and N number of days).

Resources