Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

steady_clock overflow when compared to min?

Tags:

c++

c++-chrono

The following code seems to overflow. Why?

#include <chrono>
#include <iostream>

int main() {
    auto now = std::chrono::steady_clock::now();
    auto low = std::chrono::steady_clock::time_point::min();
    auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - low).count();
    std::cout << elapsed << "\n";
    return 0;
}

I would expect low to be the earliest time point. That's how I understand the "Return value" description under https://en.cppreference.com/w/cpp/chrono/time_point/min.

So, any other value, e.g. now, should be greater and the difference now - low should be a positive duration. Unless it somehow overflows somewhere? Is it a bug (unlikely; all main compilers seem to have this issue)? Is it my misunderstanding of chrono somehwere that is at fault?

How can I fix this?


Context: I have a list of elements. Some elements are actively being used, others have a timestamp which tells when they were last used. Periodically, timestamps are checked if they are too old, and if so elements with those early timestamps are removed from the list.

A user can manually invoke a flush operation. It sets all timestamps that exist to low so that when the next check is performed, all those elements are removed.

I can set low to be now - reasonableBigButNotTooBig value to make it work, but I thought std::chrono::steady_clock::time_point::min would be more idiomatic.

like image 228
CygnusX1 Avatar asked Oct 20 '25 19:10

CygnusX1


2 Answers

std::chrono::steady_clock::time_point::min() isn't generally zero, usually std::chrono clocks use a signed 64-bit integer as the representation of the time_point. low is therefore likely to be -2^63 ticks, now is likely a positive number of ticks therefore now - low, or equivalently now + 2^63, is likely to overflow.

The epoch of steady_clock isn't specified but in general all timestamps will be positive (the epoch is generally the boot time of the computer) so you can use std::chrono::steady_clock::time_point{} as a "minimum" time point instead.

like image 171
Alan Birtles Avatar answered Oct 22 '25 11:10

Alan Birtles


It overflows for the same reason the following test overflows when instantiated with int32_t:

#include <cstdint>
#include <iostream>
#include <limits>

template <class I>
void
test()
{
    I low = std::numeric_limits<std::int32_t>::min();
    I now = 2;
    std::cout << "low       = " << low << '\n';
    std::cout << "now       = " << now << '\n';
    std::cout << "now - low = " << now-low << "\n\n";
}

int
main()
{
    test<std::int32_t>();
    test<std::int64_t>();
}

Output:

low       = -2147483648
now       = 2
now - low = -2147483646

low       = -2147483648
now       = 2
now - low = 2147483650

The test demonstrates that when you subtract the minimum from a positive number, the result is greater than is representable in a given bit width. Only by using a larger bit width can the answer be computed without overflow.

In your example the overflow is happening with 64 bits instead of 32, but the same principle applies.

like image 38
Howard Hinnant Avatar answered Oct 22 '25 09:10

Howard Hinnant



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!