Хронотаймер неправильно конвертирует секунды

У меня интересная, но странная проблема с игровым таймером. Кажется, что миллисекунды работают просто отлично. Однако, когда я пытаюсь применить приведение std::chrono::seconds, я внезапно получаю 0.000000 при приведении к поплавку.

Мой таймер выглядит следующим образом:

 #include <iostream>
 #include <time.h>
 #include <chrono>


 class Timer
 {
 public:

     typedef std::chrono::high_resolution_clock Time;
     typedef std::chrono::milliseconds ms; //<--If changed to seconds, I get 0.00000
     typedef std::chrono::duration<float> fsec;

     std::chrono::high_resolution_clock::time_point m_timestamp;

     float currentElapsed;

     Timer()
     {
          m_timestamp = Time::now();
     }

     float getTimeElapsed()
     {
         return currentElapsed;
     }

     void Tick()
     {
         currentElapsed = std::chrono::duration_cast<ms>(Time::now() - m_timestamp).count();
         m_timestamp = Time::now();
     }

 public:
     //Singleton stuff
     static Timer* Instance();
     static void Create();
 };

Таймер срабатывает один раз за кадр. Так, например, я обычно получаю около 33 мс на кадр. 33ms / 1000 = 0.033s секунд, так что должно быть достаточно битового пространства для этого.

Любые идеи о том, что, возможно, происходит?

Любая помощь приветствуется!

РЕДАКТИРОВАТЬ: извините, секунды, а не миллисекунды


person Serguei Fedorov    schedule 20.12.2013    source источник
comment
Где именно появляется 0.000? Вы говорите, что бросили на поплавок - куда?   -  person Joseph Mansfield    schedule 20.12.2013
comment
currentElapsed — это число с плавающей запятой, как и std::chrono::duration‹float›. Насколько я понимаю, внутренний формат не является плавающим. Переменная currentElapsed становится равной 0.0f. Если миллисекунды, возвращается ненулевое значение.   -  person Serguei Fedorov    schedule 20.12.2013


Ответы (1)


std::chrono::seconds и др. все они имеют целочисленное представление (C++11 §20.11.2 [time.syn]). Когда вы конвертируете продолжительность с высоким разрешением в продолжительность с низким разрешением, вы выполняете целочисленное деление с результирующим усечением, например,

using namespace std::chrono;
assert(duration_cast<seconds>(milliseconds{999}) == seconds{0});

Этого усечения можно избежать, переключившись на представление с плавающей запятой до масштабирования, а не после:

using namespace std::chrono;
currentElapsed = duration_cast<duration<float,std::milli>>(Time::now() - m_timestamp).count();

(Демонстрация в coliru)

Еще лучше сохранить currentElapsed как duration, чтобы сохранить "единицы", связанные с величиной:

class Timer {
    typedef std::chrono::high_resolution_clock Time;
    typedef std::chrono::duration<float> duration;

    Time::time_point m_timestamp;
    duration currentElapsed;

public:
    Timer() : m_timestamp(Time::now()) {}

    duration getTimeElapsed() const {
        return currentElapsed;
    }

    void Tick() {
        auto now = Time::now();
        currentElapsed = now - m_timestamp;
        m_timestamp = now;
    }
};
person Casey    schedule 20.12.2013