C++ 的时间库之二:Ratio
从现在开始,我们开始介绍 C++ 风格的时间处理,在这之前,首先要介绍
std::ratio
。因为 C++ 的chrono
库中的时间段(duration
)定义离不开std::ratio
,不了解std::ratio
,就很难理解duration
的定义。
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_t
。ratio
类还有两个静态成员,一个是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,类型不匹配,不能赋值
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";
}
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>
记住这些别名,有利于你看懂别人的代码,自己写代码的时候,也可以少敲几次键盘。
4 std::ratio 与编译期计算
std::ratio
的计算可以在编译期完成的,它的设计本意不是用来做分数库使用,它更多的体现是不同数值之间变换的桥梁。只要变换一下比率,就可以让一个值表达完全不同的意义,从这一点来说,std::ratio
比常量表达式更具有灵活性。
口说无凭,来看个例子,那就是本文要介绍的 C++ 时间库中的duration
。duration
表示一段持续的时间,是个时间跨度,也称为“时间间隔”。同一个时间间隔,可以用秒、毫秒来衡量,也可以用系统的 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
相关文章:
C++ 的时间库之二:Ratio
从现在开始,我们开始介绍 C 风格的时间处理,在这之前,首先要介绍std::ratio。因为 C 的 chrono库中的时间段(duration)定义离不开std::ratio,不了解std::ratio,就很难理解duration的定义。 1 st…...

使用小雅xiaoya/Emby正确的观看电影电视剧的姿势
最近有很多小伙伴来咨询关于小雅Emby全家桶的使用问题,最常见的就是在Emby上搜索出来资源之后,点击播放会提示【播放错误】,当前没有兼容的流。 这可把很多小伙伴给急坏了……于是找到小白咨询。 嗯……怎么说呢?小白并不喜欢看电…...
Java状态机
目录 1. 概念 2. 定义状态机 3. 生成一个状态机 4. 使用 1. 概念 在Java的应用开发里面,应该会有不少的人接触到一个业务场景下,一个数据的状态会发生多种变化,最经典的例子例如订单,当然还有像用户的状态变化(冻结…...
【Pandas】pandas Series isin
Pandas2.2 Series Computations descriptive stats 方法描述Series.align(other[, join, axis, level, …])用于将两个 Series 对齐,使其具有相同的索引Series.case_when(caselist)用于根据条件列表对 Series 中的元素进行条件判断并返回相应的值Series.drop([lab…...

通过VSCode直接连接使用 GPT的编程助手
GPT的编程助手在VSC上可以直接使用 选择相应的版本都可以正常使用。每个月可以使用40条,超过限制要付费。 如下图对应的4o和claude3.5等模型都可以使用。VSC直接连接即可。 配置步骤如下: 安装VSCODE 直接,官网下载就行 https://code.vis…...

一种最常见的js加密解密
前言 在前端开发的广袤天地中,你是否遭遇过一些看似“乱码”般的代码,根本无从下手理解?这其实很可能是被 _0x处理过的代码。_0x就像一位神秘的“化妆师”,能把原本清晰的代码改头换面。今天,我就来分享如何破解这些被…...
【Python爬虫(4)】揭开Python爬虫的神秘面纱:基础概念全解析
【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取ÿ…...
SMOJ 一笔画/洛谷 P7171 COCI 2020/2021 #3 Selotejp 题解
1.一笔画 题意 给出 n 行 m 列的点阵,每个点是一个字符: “.” 或 “#” ,其中“#”表示该点是障碍物。 现在小毛的问题是: 他最少要画多少笔才能把点阵里所有的“.”都覆盖完毕(被小毛画到的点就会被覆盖ÿ…...

【Java学习】继承
一、继承 子类继承父类,子类这个类变量的引用在原有的指向子类自己类变量空间的原有访问权限上,增加上了父类类变量空间的访问权限,此时子类类变量指向的空间变为了原来子类类变量空间加上父类类变量空间,此时子类类变量空间就变成…...

计时器任务实现(保存视频和图像)
下面是一个简单的计时器任务实现,可持续地每秒保存一幅图像,也可持续地每60秒保存一个视频,图像和视频均以当前时间命名: TimerTask类的实现如下: class TimerTask { public:TimerTask(const std::string& path):…...

树莓百度百科能否揭开成都树莓集团的神秘面纱?
树莓百度百科作为大众获取信息的重要渠道,在一定程度上为人们了解树莓集团提供了窗口,但要完全揭开其神秘面纱,仍存在一定局限性。 从树莓百度百科上,我们能获取到关于树莓集团的基本信息,如公司的成立时间、法定代表人…...

【如何看懂数据手册和原理图】
【如何看懂数据手册和原理图】 文章目录 【如何看懂数据手册和原理图】1.数据手册1.1去哪里看?1.2需要注意的 2.支路3.回路4.网孔5.电路定理:基尔霍夫定律**集总参数电路** 抽象理想化5.1基尔霍夫电流定律 (KCL)5.2基尔霍夫电压定律 (KVL)5.3总结 6.读懂…...

SQL 优化工具使用之 explain 详解
一、导读 对于大部分开发人员来说,平常接触的无非就是增删改查这些基本操作,创建存储过程,视图等等都是 DBA 该干的活,但是想要把这些基本操作写的近乎完美也是一件难事。 而 explain 显示了 MySQL 如何使用索引来处理 select 语…...
深度解析Unity3D渲染管线:网格、材质与GPU渲染的协同逻辑
在3D实时渲染领域,网格(Mesh)、材质(Material)和GPU渲染三者构成了虚拟世界的基石。它们如同乐高积木的零件,通过精确的协作,最终在屏幕上呈现出复杂的视觉场景。本文将从技术原理、协作机制到性…...

POI优化Excel录入
57000单词原始录入时间258S 核心代码: List<Word> wordBookList ExcelUtil.getReader(file.getInputStream()).readAll(Word.class);if (!CollectionUtil.isEmpty(wordBookList)) {for (Word word : wordBookList) {//逐条向数据库中插入单词wordMapper.insert(word);}…...

实时图像与视频超分辨率:高效子像素卷积网络(ESPCN)解析
文章目录 概要理论知识操作实操环境配置基础命令格式:效果示例 概要 超分辨率系列论文阅读卷1:Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network PDF网址:https://arxiv.org/…...

QT--对话框的切换
文章目录 前言一、主窗口ui二、创建子窗口三、步骤1.主界面------>子页面2.子界面------>主页面 四、总结 前言 之前我们学了qt中最重要的东西–信号和槽 我们现在实现这样一个demo,程序启动后弹出主界面,点击主界面的按钮弹出子窗口,…...
深入浅出:CUDA是什么,如何利用它进行高效并行计算
在当今这个数据驱动的时代,计算能力的需求日益增加,特别是在深度学习、科学计算和图像处理等领域。为了满足这些需求,NVIDIA推出了CUDA(Compute Unified Device Architecture),这是一种并行计算平台和编程模…...

Zotero PDF Translate插件配置百度翻译api
Zotero PDF Translate插件可以使用几种翻译api,虽然谷歌最好用,但是由于众所周知的原因,不稳定。而cnki有字数限制,有道有时也不行。其他的翻译需要申请密钥。本文以百度为例,进行申请 官方有申请教程: Zot…...

利用acme.sh 申请 Google 免费证书
1.Google API权限准备 获取 EAB 密钥 ID 和 HMAC 登录你的 GCP 控制台面板,进入 Public Certificate Authority API 管理页面(https://console.cloud.google.com/apis/library/publicca.googleapis.com)点击启动: 或者直接在下一…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...