当前我正在使用boost::rational<std::uint64>
来跟踪我的应用程序。
基本上,我有一个运行时间很长的时钟,它会被不同时间分辨率的不同组件滴答作响,例如1/50、1/30、1001/30000等。我想保持完美的精度,即没有浮点。boost::rational
可以很好地用于此目的,但我认为使用std::chrono::duration
进行此设计会更好。
但我的问题是,我如何在这里使用std::chrono::duration
?由于它使用了一个编译时间段,我不太明白如何在需要保持精度的场景中使用它?
如果我理解您的问题,并且如果您在编译时知道所有不同的时间分辨率,那么以下内容将满足您的要求。您可以在所有不同的时间分辨率上使用common_type
来计算正确的刻度周期,如下所示:
#include <cstdint>
#include <chrono>
struct clock
{
typedef std::uint64_t rep;
typedef std::common_type
<
std::chrono::duration<rep, std::ratio<1, 50>>,
std::chrono::duration<rep, std::ratio<1, 30>>,
std::chrono::duration<rep, std::ratio<1001, 30000>>
>::type duration;
typedef duration::period period;
typedef std::chrono::time_point<clock> time_point;
static const bool is_steady = true;
static time_point now()
{
// just as an example
using namespace std::chrono;
return time_point(duration_cast<duration>(steady_clock::now().time_since_epoch()));
}
};
这将在编译时计算出最大的刻度周期,它将准确地代表您指定的每个分辨率。例如,用这个时钟可以准确地表示:
- 1/50,有600个刻度
- 1/30,有1000个刻度
- 1001/30000,有1001个刻度
下面的代码练习这个clock
,并使用此处描述的"chrono_io"功能不仅打印出时钟的运行时刻度数,还打印出时钟刻度的编译时间单位:
#include <iostream>
#include <thread>
#include "chrono_io"
int main()
{
auto t0 = clock::now();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
auto t1 = clock::now();
std::cout << (t1-t0) << 'n';
}
对我来说,这个打印出来:
633 [1/30000]seconds
意思是:对now()
的调用之间有633个时钟刻度,每个刻度的单位是1/30000秒。如果你不想受制于"chrono_io",你可以用clock::period::num
和clock::period::den
检查你的时钟单位。
如果您的不同时间分辨率不是编译时间信息,那么您当前使用boost::rational
的解决方案可能是最好的。
您可以将周期设置为1
,并为Rep
使用浮点类型。
我怀疑你可以对boost::rational
做同样的事情,但你必须仔细观察std::chrono
,我还没有做过。查看treat_as_floating_point
和duration_values
。还要试着弄清楚标准中"算术类型或模拟算术类型的类"的含义。
有人可能会合理地争辩说,如果boost::rational
没有模拟算术类型,那么它就没有完成它的工作。但这并不一定意味着它真的做到了std::chrono::duration
所期望的一切。