估计留在C ++ 11时

2023-09-11 03:50:55 作者:有你我就幸福

我在写一个更新的进度条,每个 N 蜱是输出到的std :: ostream的:

 类progress_bar
{
上市:
  progress_bar(uint64_t中蜱)
    :_total_ticks(蜱),ticks_occured(0),
      _begin(STD ::计时:: steady_clock ::现在())
  ...
  无效打勾()
  {
    //测试以查看是否足够的进展已经经过
    //以保证更新进度条
    //这样,我们不会浪费资源印刷
    //东西并没有改变
    如果(/ *我们应该更新* /)
    {
      ...
    }
  }
私人:
  的std :: uint64_t中_total_ticks;
  的std :: uint64_t中_ticks_occurred;
  的std ::时辰:: steady_clock :: time_point _begin;
  ...
}
 

我也想输出的剩余时间。我发现另一个问题,指出剩余时间(变量名称更改为适合我的类):

TIME_LEFT =(TIME_TAKEN / _total_ticks)*(_total_ticks - _ticks_occured)

我想填补了我的课的部分是 TIME_LEFT TIME_TAKEN ,采用C + + 11的新的<计时>

我知道我需要使用的std ::时辰:: steady_clock ,但我不知道如何将它集成到code。我认为衡量时间将是最好的方式的std :: uint64_t中为纳秒。

我的问题是:

是否有℃的功能;计时> 将在纳秒转换为的std :: string的,这样说:3m12s? 我应该使用的std ::时辰:: steady_clock ::现在()每次更新我的进度条,并减去从 _begin 确定 TIME_LEFT ? 有没有更好的算法来确定 TIME_LEFT 解决方案   

是否有一个函数将纳秒转换成   一个std :: string的,这样说:3m12s?

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

  

我应该使用std ::时辰:: steady_clock ::现在()每次我更新   我的进度条,并减去从_begin确定TIME_LEFT?

是的。

  

有没有更好的算法来确定TIME_LEFT

是的。见下文。

从C出发 11 数组

修改

我有PTED滴答为时钟滴答原本misinter $ P $,当在现实中滴答有工作单位和 _ticks_occurred / _total_ticks 可除preTED为%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%, TIME_LEFT 9 * TIME_TAKEN 。这符合我的预期,假设每个工作滴答一个大致的线性时间成本。

 类progress_bar
{
上市:
  progress_bar(uint64_t中蜱)
    :_total_ticks(蜱),_ticks_occurred(0),
      _begin(STD ::计时:: steady_clock ::现在())
// ...
    {}
  无效打勾()
  {
    使用名字空间std ::时辰;
    //测试以查看是否足够的进展已经经过
    //以保证更新进度条
    //这样,我们不会浪费资源印刷
    //东西并没有改变
    如果(/ *我们应该更新* /)
    {
        //不知何故_ticks_occurred这里被更新,并且不为零
        持续时间TIME_TAKEN =时钟::现在() -  _begin;
        浮动percent_done =(浮点)_ticks_occurred / _total_ticks;
        持续时间TIME_LEFT = TIME_TAKEN *的static_cast<代表>(1 / percent_done  -  1);
        分钟minutes_left = duration_cast<分钟>(TIME_LEFT);
        秒seconds_left = duration_cast<秒>(TIME_LEFT  -  minutes_left);
    }
  }
私人:
  类型定义的std ::时辰:: steady_clock时钟;
  类型定义时钟:: time_point time_point;
  类型定义时钟::持续时间;
  类型定义时钟::代表处代表;
  的std :: uint64_t中_total_ticks;
  的std :: uint64_t中_ticks_occurred;
  time_point _begin;
  // ...
};
 

贩运的std ::时辰::工期时,您可以。这样<计时> 做所有的转换你。类型定义可以缓解与长文件名的打字。而打破时间到分秒一样简单,如上图所示。

正如他的回答bames53笔记,如果你想用我的< chrono_io> 的设施,这是很酷。您的需求可能是很简单的,你不想。这是一个主观判断。 bames53的回答是一个很好的答案。我想这些额外的细节可能也有帮助。

修改

我不小心留下了一个错误,在code以上。而且,而不只是修补上面的code,我认为这将是指出错误是一个好主意,并展示如何使用<计时> 来修复它

该错误是在这里:

 时间TIME_LEFT = TIME_TAKEN *的static_cast<代表>(1 / percent_done  -  1);
 

这里:

 的typedef时钟::持续时间;
 

在实践中 steady_clock ::病程通常是基于整型。 <计时> 把这个叫做代表(以下简称再presentation 的) 。而当 percent_done 大于50%时,系数乘以 TIME_TAKEN 将是小于1而当代表是不可或缺的,是被强制转换为0,所以这种 progress_bar 仅在第一个50%和$表现良好p $ pdicts在过去的50%0时间离开了。

的关键,固定,这是通车时间 s表示基于浮点整数点来代替。而<计时> 使这个很容易做到的。

 的typedef的std ::时辰:: steady_clock时钟;
类型定义时钟:: time_point time_point;
类型定义时钟::期期;
类型定义的std ::时辰::持续时间LT;浮动,时段和GT;持续时间;
 

时间现在有相同的滴答期间 steady_clock ::病程,但使用为重presentation。而现在的计算中 TIME_LEFT 可以离开关的static_cast:

 时间TIME_LEFT = TIME_TAKEN *(1 / percent_done  -  1);
 

下面是全包再次与这些修补程序:

 类progress_bar
{
上市:
  progress_bar(uint64_t中蜱)
    :_total_ticks(蜱),_ticks_occurred(0),
      _begin(STD ::计时:: steady_clock ::现在())
// ...
    {}
  无效打勾()
  {
    使用名字空间std ::时辰;
    //测试以查看是否足够的进展已经经过
    //以保证更新进度条
    //这样,我们不会浪费资源印刷
    //东西并没有改变
    如果(/ *我们应该更新* /)
    {
        //不知何故_ticks_occurred这里被更新,并且不为零
        持续时间TIME_TAKEN =时钟::现在() -  _begin;
        浮动percent_done =(浮点)_ticks_occurred / _total_ticks;
        持续时间TIME_LEFT = TIME_TAKEN *(1 / percent_done  -  1);
        分钟minutes_left = duration_cast<分钟>(TIME_LEFT);
        秒seconds_left = duration_cast<秒>(TIME_LEFT  -  minutes_left);
        性病::法院<< minutes_left.count()&其中;&其中; M<< seconds_left.count()&其中;&其中; S \ N的;
    }
  }
私人:
  类型定义的std ::时辰:: steady_clock时钟;
  类型定义时钟:: time_point time_point;
  类型定义时钟::期期;
  类型定义的std ::时辰::持续时间LT;浮动,时段和GT;持续时间;
  的std :: uint64_t中_total_ticks;
  的std :: uint64_t中_ticks_occurred;
  time_point _begin;
  // ...
};
 

没有什么像一个小的测试...; - )

I'm writing a progress bar class that outputs an updated progress bar every n ticks to an 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;
  ...
}

I would like to also output the time remaining. I found a formula on another question that states time remaining is (variable names changed to fit my class):

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

The parts I would like to fill in for my class are the time_left and the time_taken, using C++11's new <chrono> header.

I know I need to use a std::chrono::steady_clock, but I'm not sure how to integrate it into code. I assume the best way to measure the time would be a std::uint64_t as nanoseconds.

My questions are:

Is there a function in <chrono> that will convert the nanoseconds into an std::string, say something like "3m12s"? Should I use the std::chrono::steady_clock::now() each time I update my progress bar, and subtract that from _begin to determine time_left? Is there a better algorithm to determine time_left

解决方案

Is there a function in that will convert the nanoseconds into an std::string, say something like "3m12s"?

No. But I'll show you how you can easily do this below.

Should I use the std::chrono::steady_clock::now() each time I update my progress bar, and subtract that from _begin to determine time_left?

Yes.

Is there a better algorithm to determine time_left

Yes. See below.

Edit

I had originally misinterpreted "ticks" as "clock ticks", when in actuality "ticks" has units of work and _ticks_occurred/_total_ticks can be interpreted as %job_done. So I've changed the proposed progress_bar below accordingly.

I believe the equation:

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

is incorrect. It doesn't pass a sanity check: If _ticks_occured == 1 and _total_ticks is large, then time_left approximately equals (ok, slightly less) time_taken. That doesn't make sense.

I am rewriting the above equation to be:

time_left = time_taken * (1/percent_done - 1)

where

percent_done = _ticks_occurred/_total_ticks

Now as percent_done approaches zero, time_left approaches infinity, and when percent_done approaches 1, 'time_left approaches 0. When percent_done is 10%, time_left is 9*time_taken. This meets my expectations, assuming a roughly linear time cost per work-tick.

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;
  //...
};

Traffic in std::chrono::durations whenever you can. That way <chrono> does all the conversions for you. typedefs can ease the typing with the long names. And breaking down the time into minutes and seconds is as easy as shown above.

As bames53 notes in his answer, if you want to use my <chrono_io> facility, that's cool too. Your needs may be simple enough that you don't want to. It is a judgement call. bames53's answer is a good answer. I thought these extra details might be helpful too.

Edit

I accidentally left a bug in the code above. And instead of just patch the code above, I thought it would be a good idea to point out the bug and show how to use <chrono> to fix it.

The bug is here:

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

and here:

typedef Clock::duration duration;

In practice steady_clock::duration is usually based on an integral type. <chrono> calls this the rep (short for representation). And when percent_done is greater than 50%, the factor being multiplied by time_taken is going to be less than 1. And when rep is integral, that gets cast to 0. So this progress_bar only behaves well during the first 50% and predicts 0 time left during the last 50%.

The key to fixing this is to traffic in durations that are based on floating point instead of integers. And <chrono> makes this very easy to do.

typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::period period;
typedef std::chrono::duration<float, period> duration;

duration now has the same tick period as steady_clock::duration but uses a float for the representation. And now the computation for time_left can leave off the static_cast:

duration time_left = time_taken * (1/percent_done - 1);

Here's the whole package again with these fixes:

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;
  //...
};

Nothing like a little testing... ;-)

相关推荐