ner*_*ehl 6 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;
...
}
Run Code Online (Sandbox Code Playgroud)
我还想输出剩余的时间.我在另一个问题上找到了一个公式,说明剩余的时间是(变量名称已更改为适合我的班级):
time_left = (time_taken / _total_ticks) * (_total_ticks - _ticks_occured)
我想填补了我的课的部分是time_left
与time_taken
使用C++ 11的新<chrono>
报头.
我知道我需要使用a std::chrono::steady_clock
,但我不确定如何将其集成到代码中.我认为测量时间的最佳方法std::uint64_t
是纳秒.
我的问题是:
<chrono>
将纳秒转换成一个std::string
像"3m12s"的东西?std::chrono::steady_clock::now()
每次更新进度条时使用,并从中减去_begin
确定time_left
吗?time_left
是否有一个函数将纳秒转换为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)
Run Code Online (Sandbox Code Playgroud)
是不正确的.它没有通过健全性检查:如果_ticks_occured == 1
并且_total_ticks
很大,则time_left
大约等于(好,稍微少)time_taken
.这没有意义.
我正在重写上面的等式:
time_left = time_taken * (1/percent_done - 1)
Run Code Online (Sandbox Code Playgroud)
哪里
percent_done = _ticks_occurred/_total_ticks
Run Code Online (Sandbox Code Playgroud)
现在percent_done
接近零,time_left
接近无穷大,当percent_done
接近1时,'time_left
接近0.当percent_done
是10%时,time_left
是9*time_taken
.这符合我的期望,假设每个工作的时间成本大致是线性的.
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;
//...
};
Run Code Online (Sandbox Code Playgroud)
只要你可以,就可以在std :: chrono :: durations中进行交易.这样<chrono>
做可以为您完成所有转换.typedef可以使用长名称轻松输入.将时间分解为分钟和秒钟就像上面所示一样简单.
正如bames53在他的回答中所说,如果你想使用我的<chrono_io>
设施,那也很酷.您的需求可能很简单,您不想这样做.这是一个判断电话.bames53的答案是一个很好的答案.我认为这些额外的细节也可能有所帮助.
编辑
我不小心在上面的代码中留下了一个错误.而不只是修补上面的代码,我认为指出错误并展示如何使用<chrono>
它来修复它是一个好主意.
错误在这里:
duration time_left = time_taken * static_cast<rep>(1/percent_done - 1);
Run Code Online (Sandbox Code Playgroud)
和这里:
typedef Clock::duration duration;
Run Code Online (Sandbox Code Playgroud)
在实践steady_clock::duration
中通常基于整体类型. <chrono>
称之为rep
(表示的简称).并且当percent_done
大于50%时,乘以的因子time_taken
将小于1.并且当rep
为积分时,将被转换为0.因此,这progress_bar
仅在前50%期间表现良好并且预测在最后50%期间剩余0时间. 50%.
修复此问题的关键是在duration
s中基于浮点而不是整数进行流量处理.并且这<chrono>
使得这很容易做到.
typedef std::chrono::steady_clock Clock;
typedef Clock::time_point time_point;
typedef Clock::period period;
typedef std::chrono::duration<float, period> duration;
Run Code Online (Sandbox Code Playgroud)
duration
现在具有相同的刻度周期,steady_clock::duration
但使用a float
表示.现在计算time_left
可以省去static_cast:
duration time_left = time_taken * (1/percent_done - 1);
Run Code Online (Sandbox Code Playgroud)
以下是使用这些修复程序的整个包:
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;
//...
};
Run Code Online (Sandbox Code Playgroud)
没有什么比一点测试...... ;-)
归档时间: |
|
查看次数: |
3069 次 |
最近记录: |