В программе, которая накапливает struct timespec дельт, я выполняю следующую логику:

struct timespec accu, start, stop;

for (...) {
    // record start
    // perform some logic
    // record stop

    accu.tv_sec += stop.tv_sec - start.tv_sec;
    accu.tv_nsec += stop.tv_nsec - start.tv_nsec;
    if (accu.tv_nsec >= 1000000000L) {
        accu.tv_nsec -= 1000000000L;
        ++accu.tv_sec;
    }
} // end for loop

Однако, когда я печатаю результат, используя:

printf("%lld.%.9ld\n", (long long) accu.tv_sec, accu.tv_nsec);

Иногда я вижу такие результаты: 1.-611075708

Что я делаю не так, чтобы иметь отрицательное значение в accu.tv_nsec?

Примечание: start и stop получены с помощью clock_gettime().

4
Patrick Allaert 24 Июн 2014 в 18:41

2 ответа

Лучший ответ

Преобразуйте struct timespec в uint64_t количество наносекунд, прошедших с эпохи, и найдите дельты между ними и легко их накапливайте. Например.:

#include <time.h>
#include <stdint.h>

inline uint64_t as_nanoseconds(struct timespec* ts) {
    return ts->tv_sec * (uint64_t)1000000000L + ts->tv_nsec;
}

int main() {
    struct timespec start, stop;
    uint64_t accu_nsec = 0;

    for (...) {
        // record start
        // perform some logic
        // record stop

        accu_nsec += as_nanoseconds(&stop) - as_nanoseconds(&start);
    } // end for loop
}
6
Maxim Egorushkin 24 Июн 2014 в 16:05

Вы не можете просто добавить время, подобное этому, без надлежащей обработки переполнения / потери значимости при втором добавлении. Пример: старт = 1,99 ... с, стоп = 2,01 ... с

Это дает нам:

accu.tv_sec += 2 - 1 = 1;
accu.tv_nsec += 01... - 99.. = -98...;

Следовательно, вы должны использовать временную переменную для вычисления nsec. Если он <0, вам нужно вычесть 1 и прибавить 1000000000L к nsec.

3
Aaron Digulla 24 Июн 2014 в 14:53