C++ 估计C+中剩余的时间+;11

C++ 估计C+中剩余的时间+;11,c++,algorithm,c++11,C++,Algorithm,C++11,我正在编写一个进度条类,它每隔n向std::ostream输出一个更新的进度条: class progress_bar { public: progress_bar(uint64_t ticks) : _total_ticks(ticks), ticks_occured(0), _begin(std::chrono::steady_clock::now()) ... void tick() { // test to see if enough prog

我正在编写一个进度条类,它每隔
n
std::ostream
输出一个更新的进度条:

class progress_bar
{
public:
  progress_bar(uint64_t ticks)
    : _total_ticks(ticks), ticks_occured(0),
      _begin(std::chrono::steady_clock::now())
  ...
  void tick()
  {
    // test to see if enough progress has elapsed
    //  to warrant updating the progress bar
    //  that way we aren't wasting resources printing
    //  something that hasn't changed
    if (/* should we update */)
    {
      ...
    }
  }
private:
  std::uint64_t _total_ticks;
  std::uint64_t _ticks_occurred;
  std::chrono::steady_clock::time_point _begin;
  ...
}
我还想输出剩余的时间。我发现了一个公式,表示剩余时间为(变量名称已更改以适合我的类):

time\u left=(所用时间/\u总刻度)*(\u总刻度-\u刻度发生)

我想用C++11新的
标题为我的课程填写的部分是剩余的
时间和花费的
时间

我知道我需要使用一个
std::chrono::staid\u clock
,但我不知道如何将它集成到代码中。我假设测量时间的最佳方法是以纳秒为单位的
std::uint64\u t

我的问题是:

  • 中是否有一个函数可以将纳秒转换为
    std::string
    ,比如“3m12s”
  • 我是否应该在每次更新进度条时使用
    std::chrono::staid\u clock::now()
    ,并从
    \u begin
    中减去它来确定
    剩余时间
  • 是否有更好的算法来确定剩余时间

  • chrono库包括用于表示持续时间的类型。您不应该将其转换为某个“已知”单位的平坦整数。当您需要一个已知的单位时,只需使用计时类型,例如“std::chrono::nanoseconds”和
    duration\u cast
    。或者使用浮点表示法和SI比率之一创建自己的持续时间类型。例如,
    std::chrono::duration
    。没有
    持续时间\u cast
    或浮点持续时间四舍五入在编译时被禁止

    chrono的IO功能并没有进入C++11,但您可以从中获取源代码。使用此选项,您可以忽略持续时间类型,它将打印正确的单位。我不认为有任何东西可以用分、秒等来显示时间,但这样的东西应该不会太难写

    我不知道有太多的理由担心频繁地调用
    staddy\u clock::now()
    ,如果你这样问的话。我希望大多数平台都会有一个相当快的计时器来完成这类事情。不过,这确实取决于实现。显然,这给您带来了问题,因此您可能只能在
    if(/*我们是否应该更新*/)
    块中调用
    stable_clock::now()
    ,这应该对调用频率设置合理的限制

    显然,还有其他方法来估计剩余时间。例如,您可以从最后N个刻度中取平均值,而不是取迄今为止进度的平均值(这是您显示的公式所做的)。或者两者都做,取两个估计值的加权平均值

    中是否有将纳秒转换为纳秒的函数 一个std::字符串,比如说“3m12s”

    不,但我将在下面向您展示如何轻松地做到这一点

    我应该在每次更新时使用std::chrono::stable\u clock::now()吗 我的进度条,然后从中减去它,开始确定剩下的时间

    是否有更好的算法来确定剩余时间

    对。见下文

    编辑

    我最初将“滴答声”误解为“时钟滴答声”,而实际上“滴答声”有工作单位,
    \u滴答声发生/\u总滴答声
    可以解释为%job\u done。因此,我相应地更改了下面建议的
    进度条

    我相信这个等式:

    time_left = (time_taken / _total_ticks) * (_total_ticks - _ticks_occured)
    
    这是不正确的。它未通过健全性检查:如果
    \u ticks\u occurrent==1
    \u total\u ticks
    较大,则
    剩余时间
    大约等于(好的,稍微少一点)
    所用时间
    。那没有道理

    我将上述等式改写为:

    time_left = time_taken * (1/percent_done - 1)
    
    在哪里

    现在当
    完成百分比
    接近零时,
    剩余时间
    接近无穷大,当
    完成百分比
    接近1时,
    剩余时间
    接近0。当
    完成百分比
    为10%时,
    剩余时间
    9*所用时间
    。这符合我的期望,假设每个工作周期的时间成本大致呈线性

    class progress_bar
    {
    public:
      progress_bar(uint64_t ticks)
        : _total_ticks(ticks), _ticks_occurred(0),
          _begin(std::chrono::steady_clock::now())
    //  ...
        {}
      void tick()
      {
        using namespace std::chrono;
        // test to see if enough progress has elapsed
        //  to warrant updating the progress bar
        //  that way we aren't wasting resources printing
        //  something that hasn't changed
        if (/* should we update */)
        {
            // somehow _ticks_occurred is updated here and is not zero
            duration time_taken = Clock::now() - _begin;
            float percent_done = (float)_ticks_occurred/_total_ticks;
            duration time_left = time_taken * static_cast<rep>(1/percent_done - 1);
            minutes minutes_left = duration_cast<minutes>(time_left);
            seconds seconds_left = duration_cast<seconds>(time_left - minutes_left);
        }
      }
    private:
      typedef std::chrono::steady_clock Clock;
      typedef Clock::time_point time_point;
      typedef Clock::duration duration;
      typedef Clock::rep rep;
      std::uint64_t _total_ticks;
      std::uint64_t _ticks_occurred;
      time_point _begin;
      //...
    };
    
    实际上,
    稳定时钟::持续时间通常基于整数类型
    将其称为
    代表
    (表示法的缩写)。当
    完成百分比
    大于50%时,乘以
    所用时间
    的系数将小于1。当
    rep
    为整数时,则转换为0。因此,这个
    进度条只在前50%期间表现良好,在最后50%期间预测剩余时间为0

    解决这一问题的关键是使用基于浮点而非整数的
    duration
    s进行通信。而
    使这一点非常容易做到

    typedef std::chrono::steady_clock Clock;
    typedef Clock::time_point time_point;
    typedef Clock::period period;
    typedef std::chrono::duration<float, period> duration;
    
    下面是完整的软件包,包括以下修复:

    class progress_bar
    {
    public:
      progress_bar(uint64_t ticks)
        : _total_ticks(ticks), _ticks_occurred(0),
          _begin(std::chrono::steady_clock::now())
    //  ...
        {}
      void tick()
      {
        using namespace std::chrono;
        // test to see if enough progress has elapsed
        //  to warrant updating the progress bar
        //  that way we aren't wasting resources printing
        //  something that hasn't changed
        if (/* should we update */)
        {
            // somehow _ticks_occurred is updated here and is not zero
            duration time_taken = Clock::now() - _begin;
            float percent_done = (float)_ticks_occurred/_total_ticks;
            duration time_left = time_taken * (1/percent_done - 1);
            minutes minutes_left = duration_cast<minutes>(time_left);
            seconds seconds_left = duration_cast<seconds>(time_left - minutes_left);
            std::cout << minutes_left.count() << "m " << seconds_left.count() << "s\n";
        }
      }
    private:
      typedef std::chrono::steady_clock Clock;
      typedef Clock::time_point time_point;
      typedef Clock::period period;
      typedef std::chrono::duration<float, period> duration;
      std::uint64_t _total_ticks;
      std::uint64_t _ticks_occurred;
      time_point _begin;
      //...
    };
    
    课程进度\u栏
    {
    公众:
    进度条(uint64标记)
    :_总刻度(刻度),_刻度发生(0),
    _开始(标准::时钟::稳定时钟::现在()
    //  ...
    {}
    空勾()
    {
    使用名称空间std::chrono;
    //测试以查看是否已取得足够的进展
    //为了保证更新进度条
    //这样我们就不会浪费印刷资源
    //一些没有改变的东西
    如果(/*我们应该更新*/)
    {
    //不知何故,这里更新了发生的_ticks _,而不是零
    持续时间=时钟::现在()-\u开始;
    浮动百分比\u完成=(浮动)\u刻度\u发生/\u总刻度;
    剩余持续时间=所用时间*(1/完成百分比-1);
    剩余分钟数=持续时间(剩余时间);
    剩余秒数=持续时间(剩余时间-剩余分钟);
    std::cout“tick”的原因是表示进度,即:我有1000000个操作(tick)要完成。从我所能看出boost有一个
    chrono\u io
    。您推荐吗
    typedef Clock::duration duration;
    
    typedef std::chrono::steady_clock Clock;
    typedef Clock::time_point time_point;
    typedef Clock::period period;
    typedef std::chrono::duration<float, period> duration;
    
    duration time_left = time_taken * (1/percent_done - 1);
    
    class progress_bar
    {
    public:
      progress_bar(uint64_t ticks)
        : _total_ticks(ticks), _ticks_occurred(0),
          _begin(std::chrono::steady_clock::now())
    //  ...
        {}
      void tick()
      {
        using namespace std::chrono;
        // test to see if enough progress has elapsed
        //  to warrant updating the progress bar
        //  that way we aren't wasting resources printing
        //  something that hasn't changed
        if (/* should we update */)
        {
            // somehow _ticks_occurred is updated here and is not zero
            duration time_taken = Clock::now() - _begin;
            float percent_done = (float)_ticks_occurred/_total_ticks;
            duration time_left = time_taken * (1/percent_done - 1);
            minutes minutes_left = duration_cast<minutes>(time_left);
            seconds seconds_left = duration_cast<seconds>(time_left - minutes_left);
            std::cout << minutes_left.count() << "m " << seconds_left.count() << "s\n";
        }
      }
    private:
      typedef std::chrono::steady_clock Clock;
      typedef Clock::time_point time_point;
      typedef Clock::period period;
      typedef std::chrono::duration<float, period> duration;
      std::uint64_t _total_ticks;
      std::uint64_t _ticks_occurred;
      time_point _begin;
      //...
    };