Implicit conversion double to unsigned long overflow c++
Implicit conversion double to unsigned long overflow c++
I'm testing a timer based on the ctime library using the clock() function.
Please note that the code that follows is only for test purposes.
#include <ctime>
unsigned long Elapsed(void);
clock_t start = 0;
clock_t stop = 0;
int main()
{
start = std::clock();
while(1)
{
sleep(1);
cout << "Elapsed seconds: " << Elapsed() << endl;
}
return 0;
}
unsigned long Elapsed()
{
stop = std::clock();
clock_t ticks = stop - start;
double seconds = (double)ticks / CLOCKS_PER_SEC; //CLOCK_PER_SEC = 1 milion
return seconds;
}
As you can see I'm performing an implicit conversion from double to unsigned long when Elapsed() returns the calculated value.
The unsigned long limit for a 32 bit system is 2,147,483,647 and I get overflow after Elapsed() returns 2146.
Looks like the function converts "ticks" to unsigned long, CLOCK_PER_SEC to unsigned long and then it returns the value. When it converts the "ticks" it overflows.
I expected it, instead, to first calculate the value in double of "ticks"/CLOCK_PER_SEC and THEN convert it to unsigned long.
In the attempt to count more seconds I tried to return a unsigned long long data type, but the variable always overflows at the same value (2147).
Could you explain me why the compiler converts to unsigned long long "a priori" and why even with unsigned long long it overflows at the same value ?
Is there any way to write the Elapsed() function in a better way to prevent the overflow to happen ?
unsigned long
4294967295
std::clock()
seconds
0
2147
unsigned long
@M.M Edited, sorry.
– Podarce
Jul 2 at 9:14
3 Answers
3
If on your system, clock_t is a 32 bit type, then it's likely it'll wrap around after 2147 seconds like you're seeing. This is expected behavior (ref. clock). And no amount of casting will get around that. Your code needs to be able to deal with the wrap-around (either by ignoring it, or by explicitly accounting for it).
clock_t
clock
Contrary to popular belief, the behaviour on converting a floating point type such as a double to any integral type is undefined if the value cannot fit into that integral type.
double
So introducing a double in your function is a poor thing to do indeed.
double
Why not write return ticks / CLOCKS_PER_SEC; instead if you can allow for truncation and wrap-around effects? Or if not, use a unsigned long long as the return value.
return ticks / CLOCKS_PER_SEC;
unsigned long long
When it converts the "ticks" it overflows.
No, the clock itself "overflows"; the conversion has nothing to do with it. That said, the conversion to double is pointless. Your limitation is the type clock_t. See notes for example from this reference:
double
clock_t
The value returned by clock() may wrap around on some implementations. For example, on a machine with 32-bit clock_t, it wraps after 2147 seconds or 36 minutes.
One alternative, if it's available to you, is to rely on POSIX standard instead of C standard library. It provides clock_gettime which can be used to get the CPU time represented in timespec. Not only does it not suffer from this overlflow (until much longer timespan), but it also may have higher resolution than clock. The linked reference page of clock() conveniently shows example usage of clock_gettime as well.
clock_gettime
timespec
clock
clock()
clock_gettime
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
The limit for
unsigned longfor 32bit systems is4294967295, it isstd::clock(), which wraps around every 2147 seconds: en.cppreference.com/w/cpp/chrono/c/clock Sosecondsis a value between0and2147, so the implicit conversion tounsigned longis fine.– mch
Jul 2 at 8:32