C++ 的时间库之二:Ratio

news/2025/2/27 10:29:32

从现在开始,我们开始介绍 C++ 风格的时间处理,在这之前,首先要介绍std::ratio。因为 C++ 的 chrono库中的时间段(duration)定义离不开std::ratio,不了解std::ratio,就很难理解duration的定义。

ratio__2">1 std::ratio 的基本意义

std::ratio 是 C++ 11 引入的数值计算库的一部分,对应的头文件是 (如果使用时间库,只要包含头文件就可以了,这个头文件内部引用了 头文件)。有资料将其称之为分数,其实它只是提供了比例或比率的概念,并且std::ratio是个完完全全的泛型库,它的所有计算都是在编译期间完成的,其定义如下:

template<std::intmax_t Num,  std::intmax_t Denom = 1> 
class ratio;

std::intmax_t 表示系统支持的最大位宽的整数,一般 32 位系统中代表的是std::int32_t,在 64 位的系统上代表的是std::int64_tratio类还有两个静态成员,一个是ratio::num,表示约分后的分子,另一个是ratio::den,表示约分后的分母。看一下例子代码就明了了:

assert((std::ratio<24, 32>::num == 3));
assert((std::ratio<24, 32>::den == 4));
//或者:
std::cout << "std::ratio<24, 32>::num = " << std::ratio<24, 32>::num << std::endl;
std::cout << "std::ratio<24, 32>::den = " << std::ratio<24, 32>::den << std::endl;

由于std::ratio必须在编译期实例化的,所以std::ratio类的两个模板参数必须都是常量或常量表达式(constexpr):

int n = 10;
int m = 100;

std::ratio<n, m>::num; //ERROR,编译错误

const int n = 10;
const int m = 100;
std::ratio<n, m>::num; //OK

std::ratio 是个类模板,实例化后的std::ratio<24, 32>就是一个类型,可以用这个类型定义变量(内部成员 type 与之等效):

std::ratio<3, 4> a;
//std::ratio<24, 32>::type a;  //等效于上一行
assert((a.num == 3));  //注意用了 . 运算符,因为 a 是一个变量了
assert((a.den == 4));

当然,也可以用 using直接使用别名代表一个比率:

using three_fouth = std::ratio<3, 4>;
assert((three_fouth::num == 3));  //注意用了:: 运算符,因为 three_fouthes 是个 std::ratio<3, 4>类型
assert((three_fouth::den == 4));

还有一个很有意思的现象,就是std::ratio<3, 4>std::ratio<24, 32>被视为同种类型,它们的变量可以赋值和交换:

std::ratio<3, 4> a;
std::ratio<24, 32>::type b; 

b = a; //虽然没有意义,但是编译OK

但是std::ratio<24, 64>与它们就不是同类:

std::ratio<3, 4> a;
std::ratio<24, 64>::type b; 

b = a; //ERROR,类型不匹配,不能赋值

ratio__69">2 std::ratio 的计算和比较

std::ratio还支持比率的加、减、乘、除运算,但是也都是在编译器处理的,std::ratio_add()方法的两个模板参数也必须是std::ratio类型,或std::ratio类型的别名,但是不能是std::ratio类型定义的变量名。以加法的使用方法为例:

using two_third = std::ratio<2, 3>;
using one_sixth = std::ratio<1, 6>;
using sum = std::ratio_add<two_third, one_sixth>;
std::cout << "2/3 + 1/6 = " << sum::num << '/' << sum::den << '\n';

输出结果是:

2/3 + 1/6 = 5/6

除了四种基本运算,std::ratio还支持大于、大于等于、小于、小于等于、等于和不等于共六个逻辑运算,以下是判断两个比率是否是大于关系的例子:

//C++ 11 的方式
if (std::ratio_greater<std::ratio<11, 12>, std::ratio<10, 11>>::value) 
{
    std::cout << "11/12 > 10/11" "\n";
}
//C++ 17 的方式
if constexpr (std::ratio_greater_v<std::ratio<12, 13>, std::ratio<11, 12>>)
{
    std::cout << "12/13 > 11/12" "\n";
}

这些判断也都是在编译期进行的,没有任何运行开销,最终运行的代码应该是这个样子的:

if (true) 
{
    std::cout << "11/12 > 10/11" "\n";
}

ratio__110">3 std::ratio 的预定义类型

​ 为了方便代码的书写,std::ratio还提供了很多预定义比率的别名,比如:

std::nano   相当于 std::ratio<1, 1000000000>
std::micro 	相当于 std::ratio<1, 1000000>
std::milli 	相当于 std::ratio<1, 1000>
std::centi 	相当于 std::ratio<1, 100>
std::deci 	相当于 std::ratio<1, 10>
std::deca 	相当于 std::ratio<10, 1>
std::hecto 	相当于 std::ratio<100, 1>
std::kilo 	相当于 std::ratio<1000, 1>
std::mega 	相当于 std::ratio<1000000, 1>
std::giga 	相当于 std::ratio<1000000000, 1>

记住这些别名,有利于你看懂别人的代码,自己写代码的时候,也可以少敲几次键盘。

ratio__129">4 std::ratio 与编译期计算

std::ratio的计算可以在编译期完成的,它的设计本意不是用来做分数库使用,它更多的体现是不同数值之间变换的桥梁。只要变换一下比率,就可以让一个值表达完全不同的意义,从这一点来说,std::ratio比常量表达式更具有灵活性。

​ 口说无凭,来看个例子,那就是本文要介绍的 C++ 时间库中的durationduration表示一段持续的时间,是个时间跨度,也称为“时间间隔”。同一个时间间隔,可以用秒、毫秒来衡量,也可以用系统的 ticks 来衡量,在不同的衡量单位之间转换,需要专门的计算。但是来看看结合了std::ratio使用的duration是如何做这种转换的呢?来看个例子:

using namespace std::chrono;

duration<long long, std::micro> micro_dura(5000000);
//duration<double, std::ratio<1, 1000000>> micro_dura(5000000);  //与上面一行代码等价

auto sec_dura = duration_cast<duration<long long, std::ratio<1, 1>>>(micro_dura);
std::cout << "5000000 microseconds = " << sec_dura.count() << " seconds" << std::endl;

这段代码定义了一个单位是微秒的时间间隔变量,名为micro_dura,并赋值为 5000000 (微秒)。然后用duration_cast将其转换为以秒为单位的时间间隔sec_dura,其值是 5(sec_dura.count() 就是返回这个时间间隔中有多少个计数单位(周期),每个单位的意义取决于duration周期的定义)。上述代码是duration_cast是在编译期间完成的,不占用运行时间。

​ 实际上,C++ 的时间库对各种时间间隔都有预定义的别名,比如上述代码可以用更简单的形式书写:

using namespace std::chrono;

microseconds micro_dura(5000000);  //std::chrono::microseconds
auto aaa = duration_cast<seconds>(micro_dura);
std::cout << "5000000 microseconds = " << aaa.count() << " seconds" << std::endl;

再来看一个例子,统计一个 280 秒的时间间隔中包含多少个 70 秒的时间间隔(周期):

seconds sec(280); //等效于 duration<long long, std::ratio<1, 1>> sec(280);
auto bbb = duration_cast<duration<long long, std::ratio<70, 1>>>(sec);
assert((bbb.count() == 4));

这段代码中的duration<long long, std::ratio<70, 1>>表示定义了一种时间间隔类型,就是以 70 秒为周期的时间间隔类型。seconds时间库预定义的时间间隔类型,单位是秒。

关注作者的算法专栏
https://blog.csdn.net/orbit/category_10400723.html

关注作者的出版物《算法的乐趣(第二版)》
https://www.ituring.com.cn/book/3180


http://www.niftyadmin.cn/n/5858351.html

相关文章

学习Java的基础知识

Java代码的基本结构 Java 代码通常由类&#xff08;class&#xff09;、方法&#xff08;method&#xff09;和语句&#xff08;statement&#xff09;组成。以下是代码的主要部分&#xff1a; 类&#xff08;Class&#xff09;&#xff1a; Java 程序的所有代码都必须写在类中…

【项目】基于STM32F103C8T6的四足爬行机器人设计与实现(源码工程)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、测试技术。 【项目】基于STM32F103C8T6的四足爬行机器人设计与…

嵌入式八股文(四)计算机网络篇

第一章 基础概念 1. 服务 指网络中各层为紧邻的上层提供的功能调用,是垂直的。包括面向连接服务、无连接服务、可靠服务、不可靠服务。 2. 协议 是计算机⽹络相互通信的对等层实体之间交换信息时必须遵守的规则或约定的集合。⽹络协议的三个基本要素:语法、…

Python .py文件打包成.exe可执行程序,带托盘图标的可执行文件

Python .py文件打包成.exe可执行程序&#xff0c;带托盘图标的可执行文件 安装pyinstalle 查看是否安装了pyinstaller 已安装 C:\Users\Administrator>pip show pyinstaller Name: pyinstaller Version: 6.12.0 Summary: PyInstaller bundles a Python application and a…

安全问答—评估和应用安全治理原则相关

前言 安全职能需依业务战略等调整&#xff0c;通过有效安全管理计划及组织流程等保障&#xff0c;参考安全控制框架并秉持应尽关心态度&#xff0c;各角色明确责任协同保障安全&#xff0c;同时关注收购等特殊业务场景安全风险及应对措施。 根据业务战略、目标、任务和目的调…

aws服务器开放端口

aws服务器开放端口 登录aws https://ap-southeast-1.console.aws.amazon.com/console/home 搜索EC2 控制面板–>实例 进入正在运行的实例 下拉&#xff0c;找到 安全–>安全组 找到 入站规则–>编辑入站规则 比如我想开放 8000到9000的端口&#xff0c;可以这样操…

【Git Checkout 时报错 `Unlink of file failed` 的技术分析与解决方案】

Git Checkout 时报错 Unlink of file failed 的技术分析与解决方案 引言 在使用 Git 进行分支切换&#xff08;git checkout&#xff09;或文件恢复时&#xff0c;开发者偶尔会遇到以下报错&#xff1a; Unlink of file script/input_link.csv failed. Should I try again? 此…

[MySQL#1] database概述 常见的操作指令 MySQL架构 存储引擎

#1024程序员节&#xff5c;征文# 目录 一. 数据库概念 0.连接服务器 1. 什么是数据库 口语中的数据库 为什么数据不直接以文件形式存储&#xff0c;而需要使用数据库呢&#xff1f; 总结 二. ??基础操作 三. 主流数据库 四. 基础知识 服务器&#xff0c;数据库&…