How the casting of time_t works in C? - c

Please, consider the following program:
#include <stdio.h>
#include <time.h>
#define N 10000
int main ()
{
time_t begin1,end1;
float diff1;
int begin2, end2, diff2;
int i;
begin1 = time (NULL);
begin2 = time (NULL);
//consuming time
for(i=0;i<N;i++){
printf("%.2f%%\n",(i/(float)N)*100);
}
end1 = time (NULL);
end2 = time (NULL);
diff1 = difftime(end1, begin1);
diff2 = end2-begin2;
printf("%f\t%d\n",diff1, diff2);
return 0;
}
We can see that the program works perfectly. It calculates the time differences in two ways. And both provide the same answer. I'm wondering why it is possible to implicit convert the result of calling time(NULL) to an integer variable in this way.

I'm wondering why it is possible to implicit convert the result of calling time(NULL) to an integer variable in this way.
No, not for portable robust code and get consistent expected results.
difftime() returns a double. Saving as a float can certainly lose range and precision. It returns the difference in seconds.
// float diff1;
double diff1 = difftime(end1, begin1);
time_t type is a scalar. Commonly that is some wide integer and commonly a signed integer. Yet it not need be. Saving as an int can lose range (not uncommon) and precision if time_t was some floating point type (rare). time_t is often scaled in seconds, but that is not required by C. Others units are possible.
// int begin2 = time (NULL);
time_t begin2 = time (NULL);
...
// int end2 = time (NULL);
time_t end2 = time (NULL);
printf("%f\n",difftime(end2, begin2));
How the casting of time_t works in C?
Detail. OP's post does not cast anything, except go (float)N. The code does assign a time_t to an int and causes a conversion. That is similar to casting though.

First, check the prototype of time():
time_t time (time_t* timer);
where you can see that the return type is time_t, which generally is implemented as a long integer.
That is not standard though, which means you can't rely on this when you have to take portability into account.
Read more in What is ultimately a time_t typedef to?

Related

Program stops unexpectedly when I use gettimeofday() in an infinite loop

I've written a code to ensure each loop of while(1) loop to take specific amount of time (in this example 10000µS which equals to 0.01 seconds). The problem is this code works pretty well at the start but somehow stops after less than a minute. It's like there is a limit of accessing linux time. For now, I am initializing a boolean variable to make this time calculation run once instead infinite. Since performance varies over time, it'd be good to calculate the computation time for each loop. Is there any other way to accomplish this?
void some_function(){
struct timeval tstart,tend;
while (1){
gettimeofday (&tstart, NULL);
...
Some computation
...
gettimeofday (&tend, NULL);
diff = (tend.tv_sec - tstart.tv_sec)*1000000L+(tend.tv_usec - tstart.tv_usec);
usleep(10000-diff);
}
}
from man-page of usleep
#include <unistd.h>
int usleep(useconds_t usec);
usec is unsigned int, now guess what happens when diff is > 10000 in below line
usleep(10000-diff);
Well, the computation you make to get the difference is wrong:
diff = (tend.tv_sec - tstart.tv_sec)*1000000L+(tend.tv_usec - tstart.tv_usec);
You are mixing different integer types, missing that tv_usec can be an unsigned quantity, which your are substracting from another unsigned and can overflow.... after that, you get as result a full second plus a quantity that is around 4.0E09usec. This is some 4000sec. or more than an hour.... aproximately. It is better to check if there's some carry, and in that case, to increment tv_sec, and then substract 10000000 from tv_usec to get a proper positive value.
I don't know the implementation you are using for struct timeval but the most probable is that tv_sec is a time_t (this can be even 64bit) while tv_usec normally is just a unsigned 32 bit value, as it it not going to go further from 1000000.
Let me illustrate... suppose you have elapsed 100ms doing calculations.... and this happens to occur in the middle of a second.... you have
tstart.tv_sec = 123456789; tstart.tv_usec = 123456;
tend.tv_sec = 123456789; tend.tv_usec = 223456;
when you substract, it leads to:
tv_sec = 0; tv_usec = 100000;
but let's suppose you have done your computation while the second changes
tstart.tv_sec = 123456789; tstart.tv_usec = 923456;
tend.tv_sec = 123456790; tend.tv_usec = 23456;
the time difference is again 100msec, but now, when you calculate your expression you get, for the first part, 1000000 (one full second) but, after substracting the second part you get 23456 - 923456 =*=> 4294067296 (*) with the overflow.
so you get to usleep(4295067296) or 4295s. or 1h 11m more.
I think you have not had enough patience to wait for it to finish... but this is something that can be happening to your program, depending on how struct timeval is defined.
A proper way to make carry to work is to reorder the summation to do all the additions first and then the substractions. This forces casts to signed integers when dealing with signed and unsigned together, and prevents a negative overflow in unsigneds.
diff = (tend.tv_sec - tstart.tv_sec) * 1000000 + tstart.tv_usec - tend.tv_usec;
which is parsed as
diff = (((tend.tv_sec - tstart.tv_sec) * 1000000) + tstart.tv_usec) - tend.tv_usec;

C - erroneous output after multiplication of large numbers

I'm implementing my own decrease-and-conquer method for an.
Here's the program:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
double dncpow(int a, int n)
{
double p = 1.0;
if(n != 0)
{
p = dncpow(a, n / 2);
p = p * p;
if(n % 2)
{
p = p * (double)a;
}
}
return p;
}
int main()
{
int a;
int n;
int a_upper = 10;
int n_upper = 50;
int times = 5;
time_t t;
srand(time(&t));
for(int i = 0; i < times; ++i)
{
a = rand() % a_upper;
n = rand() % n_upper;
printf("a = %d, n = %d\n", a, n);
printf("pow = %.0f\ndnc = %.0f\n\n", pow(a, n), dncpow(a, n));
}
return 0;
}
My code works for small values of a and n, but a mismatch in the output of pow() and dncpow() is observed for inputs such as:
a = 7, n = 39
pow = 909543680129861204865300750663680
dnc = 909543680129861348980488826519552
I'm pretty sure that the algorithm is correct, but dncpow() is giving me wrong answers.
Can someone please help me rectify this? Thanks in advance!
Simple as that, these numbers are too large for what your computer can represent exactly in a single variable. With a floating point type, there's an exponent stored separately and therefore it's still possible to represent a number near the real number, dropping the lowest bits of the mantissa.
Regarding this comment:
I'm getting similar outputs upon replacing 'double' with 'long long'. The latter is supposed to be stored exactly, isn't it?
If you call a function taking double, it won't magically operate on long long instead. Your value is simply converted to double and you'll just get the same result.
Even with a function handling long long (which has 64 bits on nowadays' typical platforms), you can't deal with such large numbers. 64 bits aren't enough to store them. With an unsigned integer type, they will just "wrap around" to 0 on overflow. With a signed integer type, the behavior of overflow is undefined (but still somewhat likely a wrap around). So you'll get some number that has absolutely nothing to do with your expected result. That's arguably worse than the result with a floating point type, that's just not precise.
For exact calculations on large numbers, the only way is to store them in an array (typically of unsigned integers like uintmax_t) and implement all the arithmetics yourself. That's a nice exercise, and a lot of work, especially when performance is of interest (the "naive" arithmetic algorithms are typically very inefficient).
For some real-life program, you won't reinvent the wheel here, as there are libraries for handling large numbers. The arguably best known is libgmp. Read the manuals there and use it.

Why am I unable to store my data in long data type?

int power(int first,int second) {
int counter1 = 0;
long ret = 1;
while (counter1 != second){
ret *= first;
counter1 += 1;
}
return ret;
}
int main(int argc,char **argv) {
long one = atol(argv[1]);
long two = atol(argv[2]);
char word[30];
long finally;
printf("What is the operation? 'power','factorial' or 'recfactorial'\n");
scanf("%20s",word);
if (strcmp("power",word) == 0){
finally = power(one,two);
printf("%ld\n",finally);
return 0;
}
}
This function is intended to do the "power of" operation like on the calculator, so if I write: ./a.out 5 3 it will give me 5 to the power of 3 and print out 125
The problem is, in cases where the numbers are like: ./a.out 20 10, 20 to the power of 10, I expect to see the result of: 1.024 x 10^13, but it instead outputs 797966336.
What is the cause of the current output I am getting?
Note: I assume that this has something to do with the atol() and long data types. Are these not big enough to store the information? If not, any idea how to make it run for bigger numbers?
Sure, your inputs are long, but your power function takes and returns int! Apparently, that's 32-bit on your system … so, on your system, 1.024×1013 is more than int can handle.
Make sure that you pick a type that's big enough for your data, and use it consistently. Even long may not be enough — check your system!
First and foremost, you need to change the return type and input parameter types of power() from int to long. Otherwise, on a system where long and int are having different size,
The input arguments may get truncated to int while you're passing long.
The returned value will be casted to int before returning, which can truncate the actual value.
After that, 1.024×1013 (10240000000000) cannot be held by an int or long (if 32 bits). You need to use a data type having more width, like long long.
one and two are long.
long one = atol(argv[1]);
long two = atol(argv[2]);
You call this function with them
int power(int first, int second);
But your function takes int, there is an implicit conversion here, and return int. So now, your long are int, that cause an undefined behaviour (see comments).
Quick answer:
The values of your power function get implicitly converted.
Change the function parameters to type other then int that can hold larger values, one possible type would be long.
The input value gets type converted and truncated to match the parameters of your function.
The result of the computation in the body of the function will be again converted to match the return type, in your case int: not able to handle the size of the values.
Note1: as noted by the more experienced members, there is a machine-specific issue, which is that your int type is not handling the usual size int is supposed to handle.
1. To make the answer complete
Code is mixing int, long and hoping for an answer the exceeds long range.
The answer is simply the result of trying to put 10 pounds of potatoes in a 5-pound sack.
... idea how to make it run for bigger numbers.
Use the widest integer available. Examples: uintmax_t, unsigned long long.
With C99 onward, normally the greatest representable integer will be UINTMAX_MAX.
#include <stdint.h>
uintmax_t power_a(long first, long second) {
long counter1 = 0;
uintmax_t ret = 1;
while (counter1 != second){ // number of iterations could be in the billions
ret *= first;
counter1 += 1;
}
return ret;
}
But let us avoid problematic behavior with negative numbers and improve the efficiency of the calculation from liner to exponential.
// return x raised to the y power
uintmax_t pow_jululu(unsigned long x, unsigned long y) {
uintmax_t z = 1;
uintmax_t base = x;
while (y) { // max number of iterations would bit width: e.g. 64
if (y & 1) {
z *= base;
}
y >>= 1;
base *= base;
}
return z;
}
int main(int argc,char **argv) {
assert(argc >= 3);
unsigned long one = strtoul(argv[1], 0, 10);
unsigned long two = strtoul(argv[2], 0, 10);
uintmax_t finally = pow_jululu(one,two);
printf("%ju\n",finally);
return 0;
}
This approach has limits too. 1) z *= base can mathematically overflow for calls like pow_jululu(2, 1000). 2) base*base may mathematically overflow in the uncommon situation where unsigned long is more than half the width of uintmax_t. 3) some other nuances too.
Resort to other types e.g.: long double, Arbitrary-precision arithmetic. This is likely beyond the scope of this simple task.
You could use a long long which is 8 bytes in length instead of the 4 byte length of long and int.
long long will provide you values between –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. This I think should just about cover every value you may encounter just now.

Subtracting two time interval

I wanted to subtract two time interval. here one time interval is 5hour 30 minute and other is current time.the code is written as follow.
main()
{
int Time1;
int Time2;
int hour=10;
int minute=5;
int second=13;
int h; int m;
int Ntime;
Time1=(60*5)+(30);
Time2=60*hour+minute;
Ntime=Time2-Time1;
m=(Ntime%60);
Ntime=Ntime/60;
h=(int)(Ntime);
printf("hour after subtraction is : %d hour %d min",h,m)
}
I have not looked at any logical errors in your program but the error you post is due to the fact that the mod operator i.e. % expects the operand to be integer. So if you modify your code in this way, it should remove the error.
main()
{
int Time1;
int Time2;
int hour=10;
int minute=5;
int second=13;
int h; int m;
int Ntime; //double has been changed to int
double Ntime2;
Time1=(3600*5)+(60*30);
Time2=(3600*hour)+(60*minute)+second;
Ntime=Time2-Time1;
Ntime2=((double)((Ntime%60)/100) + (double)(Ntime/60));
h=(int)(Ntime2);
m=((Ntime2 - (double)h)*100);
printf("hour after subtraction is : %d hour %d min",h,m)
}
There is too much type casting involved in your code, you should look for a simpler way to do this. Look into the time.h header file, you may find something useful to work with.
The % operator is meant for integer values only. It won't work with a double variable.
Change your code to:
Ntime = (((int)Ntime%60) / 100 + (Ntime / 60));
change your statement of calculating Ntime to,
Ntime=((float)((int)Ntime%60)/100+(Ntime/60));
you need to type cast to float/double otherwise /100 will result in integer so fractional part will be truncated.

How to printf a time_t variable as a floating point number?

I'm using a time_t variable in C (openMP enviroment) to keep cpu execution time...I define a float value sum_tot_time to sum time for all cpu's...I mean sum_tot_time is the sum of cpu's time_t values. The problem is that printing the value sum_tot_time it appear as an integer or long, by the way without its decimal part!
I tried in these ways:
to printf sum_tot_time as a double being a double value
to printf sum_tot_time as float being a float value
to printf sum_tot_time as double being a time_t value
to printf sum_tot_time as float being a time_t value
The resolution of time_t is at most one second on most platforms. That is, on most platforms, time_t will be an integer (32- or 64-bit) value counting the number of seconds elapsed since midnight of Jan 1st 1970 (UTC), and can only achieve one-second resolution.
Therefore, a sum of time_t values will also only exhibit one-second resolution (no decimal part, even after converting to double.)
The above having been said, what native or OpenMP call are you using to obtain the time_t values that you are attempting to accumulate?
If using either the native *nix getrusage() call to fill out an rusage structure (provided your platform supports it) with user/kernel times, or if using gettimeofday() to get wall time, then use both the tv_sec and tv_usec fields of struct timeval to generate a double value (of millisecond-or-better resolution, typically), and use that instead of time_t in your calculations:
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
Correspondingly, you can use GetThreadTimes/GetProcessTimes for user/kernel times or _ftime for wall time on Windows platforms, then combine FILETIME::dwHighDateTime/dwLowDateTime.
I'm not sure if you have access to standard *nix system calls ( or if this is relevant to specifically to what you're doing ), but if you do you can use the timeval struct and gettimeofday. For example, to print out a timestamp with six decimal places of precision which produces a tcpdump style time stamp ( courtesy of Steven UNP )
#include "unp.h"
#include <time.h>
char *
gf_time(void)
{
struct timeval tv;
time_t t;
static char str[30];
char *ptr;
if (gettimeofday(&tv, NULL) < 0)
err_sys("gettimeofday error");
t = tv.tv_sec; /* POSIX says tv.tv_sec is time_t; some BSDs don't agree. */
ptr = ctime(&t);
strcpy(str, &ptr[11]);
/* Fri Sep 13 00:00:00 1986\n\0 */
/* 0123456789012345678901234 5 */
snprintf(str+8, sizeof(str)-8, ".%06ld", tv.tv_usec);
return(str);
}

Resources