0

I am having an interesting, yet strange issue with my game timer. It seems like the milliseconds works just fine. However, when I try to apply the std::chrono::seconds cast I suddenly get 0.000000 when casting to a float.

My timer is as follows:

 #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();
 };

The timer gets ticked once per frame. So, for instance I normally get about 33ms per frame. 33ms / 1000 = 0.033s seconds so there should be plenty of bit space to hold that.

Any ideas on what maybe going on?

Any help is greatly appreciated!

EDIT: Sorry, Seconds, not Milliseconds

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
Serguei Fedorov
  • 7,763
  • 9
  • 63
  • 94
  • Where exactly does the `0.000` show up? You say you cast to a float - where? – Joseph Mansfield Dec 20 '13 at 19:01
  • currentElapsed is a float, so is std::chrono::duration. From what I understand, the internal format is not a float. The currentElapsed variable ends up being 0.0f. If milliseconds, it returns a non-zero value. – Serguei Fedorov Dec 20 '13 at 19:04

1 Answers1

1

std::chrono::seconds et al. are all specified to have integral representations (C++11 §20.11.2 [time.syn]). When you convert a high-resolution duration to a low-resolution duration, you are performing integer division with resulting truncation, e.g,

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

You can avoid this truncation by switching to a floating point representation before scaling instead of after:

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

(Demo at coliru)

Better yet, store currentElapsed as a duration to keep the "units" associated with the magnitude:

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;
    }
};
Casey
  • 41,449
  • 7
  • 95
  • 125