0

I have a weird problem with the value returned by my class called Timer (that uses std::chrono).

If I keep the std::cout commented, I have the feeling that delta returned by timer.restart() gets a very low value (it takes 3 or 4 times longer to reach 10.f). I tried to display it, but as I said above, uncommenting the std::cout solves the problem.

My timer does its job well in others parts of the application, so I don't think the problem is in there.

void Party::gameOver(float delta)
{
    _delta += delta;
    // std::cout << _delta << std::endl; // if I uncomment this the problem is solved
    if (_delta > 10.0000f) {
        // ...
        _state = GameStatusType::Waiting;
        _delta = 0;
    }
}

This method is called here:

void Party::loop(void)
{
    Timer timer;

    while (!isFinished())
    {
        float delta = timer.restart(); // return in second

        switch (_state)
        {
        // ...
        case GameStatusType::GameOver:
            gameOver(delta);
            break;
        }
    }
}

The method "loop" is called in a thread like below:

void Party::run(void)
{
    _party = std::thread(&Party::loop, shared_from_this());
}

I don't know if this can help, but I execute this code on Visual Studio 2015 on Windows 10. If you need further information, just ask.

TriskalJM
  • 2,393
  • 1
  • 19
  • 20
Stéphane G.
  • 127
  • 1
  • 15
  • What kind of granularity does your timer have? One tenth of one second, a millisecond? If you have a method on `timer` that simply returns the total time since it first started without resetting itself, have you tried using that and then calculating whether the party is finished based off the passed `delta` without taking into account your internal `_delta` variable? – jaggedSpire Dec 13 '16 at 16:03
  • Usually the restart() returns nearly between 0.001 and 0.01, and yes the timer restart itself in the restart() method. The problem occurs only if there isn't std::cout. – Stéphane G. Dec 13 '16 at 16:07
  • I'm asking, because if there's a fairly low resolution in your time, then the presence of the `std::cout` call could push the timer's measured time since reset up by one (time unit) in a rounding error. If it's otherwise lower than that, and the rounding error instead introduces an artificially low value, again due to rounding error, the `delta` will take longer to sum to 10. – jaggedSpire Dec 13 '16 at 16:09
  • With that said, that seems like a reasonable resolution to me. Would you mind humoring me and seeing what happens to the problem if you don't reset and instead pass the whole `delta` into the function on each call, and just set `_delta` to the passed in value instead of summing? If there's a relatively large error introduced by rounding, the total time will mitigate the issues called by rounding by keeping the error at 1*(average epsilon) instead of 10*Hz*(average epsilon). If the error were normally distributed that wouldn't be an issue so much, but I think that might not be the case. – jaggedSpire Dec 13 '16 at 16:11
  • well, had a mean of 0, rather than normally distributed. – jaggedSpire Dec 13 '16 at 16:22
  • I tried but I have to reset the timer, otherwise the _delta > 10 as soon as I call the function. Also, I tried to pass delta in double or in milliseconds instead of seconds, but the problem still remains, so this isn't a rounded problem I think. – Stéphane G. Dec 13 '16 at 16:46
  • hm. Well, the only other idea I have is trying to get the timing information on the loops for the commented-out std::cout, by instead appending the time to a vector, and then printing everything out when you're no longer in the loop. Using a vector should be quick enough to have much less of an effect on the timing mechanism, so you can see what kind of times you're getting there, – jaggedSpire Dec 13 '16 at 16:53
  • Additionally, you should be made aware that [high resolution clock might *not* have as high a resolution as you think it should](http://stackoverflow.com/questions/16299029), depending on the compiler you're using. – jaggedSpire Dec 13 '16 at 16:58
  • Are you [*sure*](http://coliru.stacked-crooked.com/a/47325f9746fa4243) there's no rounding error? – jaggedSpire Dec 13 '16 at 17:19
  • It looks like there is a rounded error yes but I not understand how. I'm just summing 2 double. Maybe it's an OS / compiler issue ? – Stéphane G. Dec 13 '16 at 17:29
  • I think I have found. The loop goes too fast and summing 2 double with high precision is surely bugged in windows. I'm going to check that. – Stéphane G. Dec 13 '16 at 17:34
  • Okay it's that ... All that for this. Thanks for your help I really appreciate ! – Stéphane G. Dec 13 '16 at 17:41
  • 1
    It's a rounding error because the resolution of the timer is too low to correctly measure elapsed time less than either 1ms or 1us. It returns 0 when the time is too short to be measured, so if you're summing values, it'll look like there's no time elapsed at all. `cout` fixes this because i/o is very slow, and pushes it above the threshold where the time elapsed may be measured. It's not a issue with floating point precision--you're using doubles, and that gives you 15 decimal points of precision. When you're storing seconds, that's *femtosecond* precision. – jaggedSpire Dec 13 '16 at 17:45
  • The timing issue is one of the reasons why when profiling small amounts of code, people will run the loop thousands of times--execution will take too little time otherwise. – jaggedSpire Dec 13 '16 at 17:51

2 Answers2

0

One possibility is the windows console is really slow, there was many topic about this. You may try use overlapped io to write to console to see if it's improved.

Tiger Hwang
  • 300
  • 1
  • 5
  • 16
0

The problem was just the loop was going too fast. Just added a Sleep.

Stéphane G.
  • 127
  • 1
  • 15