С++ 11 std:: chrono вычесть сейчас и мин.

Мне кажется, что я немного с ума схожу с этим, но это просто не имеет смысла для меня. На мой взгляд, если я вычитаю минимальную точку времени из любой точки времени, возвращаемой вызовом now(), я всегда должен получать положительную продолжительность, но этого не происходит.

#include <chrono>
#include <iostream>

typedef std::chrono::steady_clock myclock;

int main(int argc, char **argv) {
        myclock::time_point min = myclock::time_point::min();
        myclock::time_point now = myclock::now();
        auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now - min).count();
        std::cout << millis << std::endl;
}

Почему это печатает отрицательное целое число, а не положительное целое число? (clang 3.3 или g++ 4.8.1)

Ответ 1

Как уже отмечалось, это результат переполнения. Помните, что минимальное значение, которое подписываемый тип может представлять, примерно такой же величины, как и наибольший. Если now положительно, то разница между now и min будет иметь большую величину, чем min, что означает, что она имеет большую величину, чем может представлять наибольшее значение типа.

Если вы хотите гарантировать положительную продолжительность, вместо того, чтобы использовать минимум, вы можете вместо этого использовать устойчивые часы, а затем использовать начальное время программы в качестве базы. Продолжительность встроенных часов определяется таким образом, что продолжительность должна быть в состоянии представлять диапазон не менее пары сотен лет, поэтому, если ваша программа работает дольше, чем вы получите положительную длительность.

Другой вариант - выбрать часы, в которых известно, что эпоха в прошлом и просто сказать

Clock::now().time_since_epoch();

Ответ 2

Вы переполняете счетчик, который на моей машине является signed long long

#include <chrono>
#include <iostream>
#include <limits.h>
using namespace std;

typedef std::chrono::steady_clock myclock;

int main(int argc, char **argv) {
    myclock::time_point min = myclock::time_point::min();
    long long minl = reinterpret_cast<long long&>(min);
    cout << reinterpret_cast<long long&>(min) << endl;

    auto now = myclock::now();
    long long nowl = reinterpret_cast<long long&>(now);
    cout << reinterpret_cast<long long&>(now) << endl;

    cout << (nowl-minl) << endl;

    cout << "max of signed long long:" << LLONG_MAX << endl;

    auto millis = std::chrono::duration_cast<std::chrono::seconds>(now - min).count();
    //std::cout << millis << std::endl;
}

Вывод:

-9223372036854775808
13924525439448122
-9209447511415327686
max of signed long long:9223372036854775807

Ответ 3

Здесь, что я думаю, происходит (от того, что я наблюдаю на своем отладчике в Apple-llvm 5.0):

myclock::time_point::min() возвращает самую раннюю временную точку, которая обычно внутренне представляется целым типом, например long long int. Минимум такого типа обычно numeric_limits<long long int>::min, что составляет -2 ^ 63. Это значение является особенным, поскольку если вы его отрицаете, вы получаете одно и то же значение, через целочисленное переполнение (поскольку максимальный длинный длинный int равен 2 ^ 63 -1):

- (- 2 ^ 63) == 2 ^ 63 == (2 ^ 63 - 1) + 1 == -2 ^ 63 (переполнением)

Такая же логика применяется к вычитанию. Все это означает, что целочисленное переполнение делает (now - min) фактически эквивалентным (now + min), что обязательно отрицательно.