Ограничения библиотеки C ++ chrono? - PullRequest
0 голосов
/ 07 мая 2020

Я извлек следующий простой код из более крупного проекта. Я пытаюсь моделировать фьючерсные даты день за днем, извлекая день, месяц, год. Я использую библиотеку std :: chrono. Через определенное количество дней (примерно 8835 дней на моем компьютере) дата сбивается. Я пытался:

  • Игра с флагом оптимизации g ++
  • Запуск с valgrind
  • Ищу документацию chrono об ограничениях

Можете ли вы воспроизвести это поведение?

// COMPILE OK && RUN KO (wandbox)
// g++ prog.cc -O2 -march=native -std=c++11

// COMPILE OK && RUN OK (wandbox)
// clang++ prog.cc -Wall -Wextra -std=c++11

#include <iostream>
#include <chrono>

using namespace std;

int main(int ac, char* av[])
{
  (void) ac; (void) av;
  auto faketime = chrono::system_clock::now();

  for( int i=0; i<100000; ++i) {
    // doDaily();
    faketime += chrono::hours(24);
    time_t ftime = chrono::system_clock::to_time_t(faketime);
    if( i% 1000 == 0)
         cout << "faketime (" << ftime << ") is : " << ctime(&ftime) << endl;
  } 
  auto currtime = chrono::system_clock::now();
  time_t cutime = chrono::system_clock::to_time_t(currtime);
  cout << "currtime is : " << ctime(&cutime);
  return 0;
} 

РЕЗУЛЬТАТ (третья строка идет не так):

[...]
faketime (9105738161) is : Tue Jul 20 20:42:41 2258
faketime (9192138161) is : Mon Apr 15 20:42:41 2261
faketime (-9168205912) is : Wed Jun 21 21:27:07 1679
faketime (-9081805912) is : Tue Mar 17 21:27:07 1682
faketime (-8995405912) is : Mon Dec 11 21:27:07 1684
currtime is : Thu May  7 12:48:56 2020

EDITED:

  • Добавлено где именно он идет не так.
  • Я тестировал этот код на https://wandbox.org/: я могу воспроизвести проблему с g cc 11, но он работает нормально с clang ++
  • Похоже, что есть ограничение, но компиляция только с g ++.

1 Ответ

2 голосов
/ 07 мая 2020

Вы столкнулись с переполнением в system_clock::time_point.

Точность system_clock::time_point зависит от платформы:

  • g cc: наносекунды
  • Windows: 1/10 микросекунды
  • clang / libc ++: микросекунд

Но представление одинаково на всех трех платформах: 64-битный интеграл со знаком. И все это соответствует.

64 бита наносекунд со знаком дают вам диапазон примерно +/- 292 года. Для system_clock этот диапазон сосредоточен на 01.01.1970. Так что переполнение в 2262 году - это нормально.

Если вам нужен больший диапазон, вы можете уменьшить свою точность. Например:

auto faketime = chrono::time_point_cast<chrono::microseconds>(chrono::system_clock::now());

Можно программно проверить пределы time_point с помощью функций-членов time_point stati c min() и max().

Update

Диапазон в микросекундах примерно +/- 292 тысяча лет. Я не уверен, что такое диапазон на ctime, но я был бы удивлен, если бы он мог форматировать даты так далеко в прошлом / будущем.

...