估计C ++ 11中剩下的时间

时间:2012-03-02 22:47:46

标签: 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 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;
  ...
}

我还想输出剩余的时间。我在another question上找到了一个公式,表明剩余时间是(变量名称已更改为适合我的班级):

time_left = (time_taken / _total_ticks) * (_total_ticks - _ticks_occured)

我想要为我的班级填写的部分是time_lefttime_taken,使用C ++ 11的新<chrono>标题。

我知道我需要使用std::chrono::steady_clock,但我不确定如何将其集成到代码中。我认为衡量时间的最佳方法是std::uint64_t为纳秒。

我的问题是:

  1. <chrono>中是否有一个函数可以将纳秒转换为std::string,比如&#34; 3m12s&#34;?
  2. 每次更新进度条时都应该使用std::chrono::steady_clock::now(),并从_begin中减去time_left以确定time_left吗?
  3. 是否有更好的算法来确定{{1}}

2 个答案:

答案 0 :(得分:7)

  

是否存在将纳秒转换为的函数   一个std :: string,比如说“3m12s”?

没有。但我会告诉你如何在下面轻松地做到这一点。

  

每次更新时都应该使用std :: chrono :: steady_clock :: now()   我的进度条,并从_begin中减去它以确定time_left?

  

是否有更好的算法来确定time_left

是。见下文。

修改

我最初误将“滴答”误解为“时钟滴答”,而实际上“滴答”具有工作单位,而_ticks_occurred/_total_ticks可以解释为%job_done。所以我已相应更改了下面的建议progress_bar

我相信等式:

time_left = (time_taken / _total_ticks) * (_total_ticks - _ticks_occured)

不正确。它没有通过完整性检查:如果_ticks_occured == 1_total_ticks很大,那么time_left大约等于(好,稍微少)time_taken。这没有意义。

我正在重写上面的等式:

time_left = time_taken * (1/percent_done - 1)

,其中

percent_done = _ticks_occurred/_total_ticks

现在当percent_done接近零时,time_left接近无穷大,当percent_done接近1时,'time_left接近0.当percent_done为10%时,{ {1}}是time_left。这符合我的期望,假设每个工作的时间成本大致是线性的。

9*time_taken

只要你能,就可以在std :: chrono :: durations中进行交易。这样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; //... }; 为您完成所有转化。 typedef可以使用长名称轻松输入。将时间分解为分钟和秒钟就像上面所示一样简单。

正如bames53在他的回答中所说,如果你想使用我的<chrono>设施,那也很酷。您的需求可能很简单,您不想这样做。这是一个判断电话。 bames53的答案是一个很好的答案。我认为这些额外的细节也可能有所帮助。

修改

我不小心在上面的代码中留下了一个错误。而不只是修补上面的代码,我认为指出错误并展示如何使用<chrono_io>来修复它是个好主意。

错误在这里:

<chrono>

在这里:

duration time_left = time_taken * static_cast<rep>(1/percent_done - 1);

实际上typedef Clock::duration duration; 通常基于整数类型。 steady_clock::duration将此称为<chrono>表示的缩写)。当rep大于50%时,乘以percent_done的因子将小于1.当time_taken为整数时,会将其强制转换为0.所以此{ {1}}仅在前50%期间表现良好,并预测在最后50%期间剩余0时间。

解决此问题的关键是在基于浮点而不是整数的rep中进行流量传输。 progress_bar使这很容易做到。

duration

<chrono>现在与typedef std::chrono::steady_clock Clock; typedef Clock::time_point time_point; typedef Clock::period period; typedef std::chrono::duration<float, period> duration; 具有相同的刻度周期,但使用duration表示。现在steady_clock::duration的计算可以省去static_cast:

float

以下是使用这些修复程序的整个软件包:

time_left

没有什么比稍微测试......; - )

答案 1 :(得分:3)

计时库包括用于表示持续时间的类型。您不应该将其转换为某个“已知”单位的平整数。当你想要一个已知的单位时,只需使用计时类型,例如: 'std :: chrono :: nanoseconds'和duration_cast。或者使用浮点表示和SI比率之一创建自己的持续时间类型。例如。 std::chrono::duration<double,std::nano>。如果没有duration_cast或浮点持续时间,则在编译时禁止舍入。

chrono的IO工具没有进入C ++ 11,但你可以从here获得源代码。使用它你可以忽略持续时间类型,它将打印正确的单位。我认为没有任何东西会以分钟,秒等显示时间,但这样的事情不应该太难写。

我不知道有太多理由担心经常拨打steady_clock::now(),如果这是你的要求。我希望大多数平台都有一个非常快的计时器来处理这类事情。它确实取决于实现。显然它会给你带来问题,所以也许你只能在steady_clock::now()块内调用if (/* should we update */),这应该对呼叫频率设置一个合理的限制

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