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 ?





The limit for unsigned long for 32bit systems is 4294967295, it is std::clock(), which wraps around every 2147 seconds: en.cppreference.com/w/cpp/chrono/c/clock So seconds is a value between 0 and 2147, so the implicit conversion to unsigned long is fine.
– mch
Jul 2 at 8:32


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.

Popular posts from this blog

How to add background colour in existing image using Swift?

Moria Casán

How to make file upload 'Required' in Contact Form 7?